Why does GetActiveObject fail to detect running instance of Outlook? - delphi

I am facing an issue in my windows7 32bit Pc(on i3).I have Outlook 2010 and Delphi 7 on it.
I am using following code to detect Outlook is running or not.
ClassID := ProgIDToClassID(ClassName);
Result := (GetActiveObject(ClassID, nil, Unknown) = S_OK);
This fails, ie, result become false and yet in other PCs this working fine.
The error I'm getting is MK_E_Unavailable.
Update:
May be it just happening with me only.
procedure TForm1.Button1Click(Sender: TObject);
function IsObjectActive(ClassName: string): Boolean;
var
ClassID: TCLSID;
Unknown: IUnknown;
begin
try
ClassID := ProgIDToClassID(ClassName);
Result := (GetActiveObject(ClassID, nil, Unknown) =S_OK );
except
Result := False;
end;
end;
begin
if IsObjectActive('Outlook.Application') Then
ShowMessage('OutLook is there.')
else
ShowMessage('OutLook is not there.')
end;
Plz note OL is running and
When I am running the created exe, I am getting message "OutLook is there".
when I am running from Delphi IDE, I am getting Message 'OutLook is not there.'
This happens always, I am using Delphi 7 on Windows 7, running with Run as Admin. Kindly tell me why this happening and how can I fix this.
What's the issue of Delphi 7 on Windows 7.
Please suggest.

Here's the entry for GetActiveObject.
http://msdn.microsoft.com/en-us/library/a276e30c-6a7f-4cde-9639-21a9f5170b62%28VS.85%29
If you want to decode the error, you need to find out what the HResult means.
Wikipedia has a link to a ERR.EXE utility from MS that will translate the HResult code into an error description. For COM HResults see: http://matthewbass.com/2005/11/15/decoding-com-hresult-error-codes/.
note the download link in the article is broken, here's a working link: http://www.softlookup.com/display.asp?id=7113
Once you know what the error is, update the question.
If you want to know whether a process is running without using OLE, see: How to check if a process is running using Delphi?
Another option might to use FindWindowEx to check for Outlook 2010 specific windows.
You can use WinID (a spy++ clone) to see the windows used by Outlook 2010.

I was facing the same issue and I found the solution.
It's simple, If Outlook is already running, it MUST have the same rights as the process that is trying to use it.
In simple words, if you are running Outlook with admin rights, you must execute your app with admin rights.
Your problem must be that you are running Outlook without admin rights, and Delphi IDE with admin rights. So when you are launching your app from within IDE, the rights doesn't match, and you get the error. This is why when running your app outside the IDE it works as expected. Because outside IDE your app runs without admin rights.
Try to match the rights. This is something to take into account for the end user environment too.
Also, the UAC under Windows Vista and later is known to cause multiple issues with these type of things. If everything else fails, disable UAC (User Account Control, you will find it under your account options) and see what happens.

try to use rctrl_renwnd32
try this:
(FindWindow('rctrl_renwnd32', nil) <> 0)
http://users.skynet.be/am044448/Programmeren/VBA/vba_class_names.htm

Related

Delphi RAD Studio 10.2, unable to browse windows system folder using FileOpenDialog

I need to be able to enumerate the folders present under C:\Windows\system32\dns on a Windows server 2016 instance running Windows DNS server.
Having tried FindFirst()/FindNext() and getting no results, I built a quick VCL Forms App to understand what was happening. I have a TButton and a TEdit, and the button's OnClick is below:
procedure TForm1.Button1Click(Sender: TObject);
begin
FDir := 'C:\Windows\System32\';
with TFileOpenDialog.Create(nil) do
try
Title := 'Select Directory';
Options := [fdoPickFolders, fdoPathMustExist, fdoForceFileSystem];
OkButtonLabel := 'Select';
DefaultFolder := FDir;
FileName := FDir;
if Execute then
Edit1.Text := Filename;
finally
Free;
end;
end;
When I run this - either as Administrator, or normally, on the server - and try to browse to the folder C:\Windows\system32\dns\ in the FileOpenDialog, I get an error:
Windows can't find 'C:\Windows\system32\dns'. Check the spelling and try again.
However, I know the folder exists, and I can browse it using Windows Explorer on the server, so there must be an issue with the Delphi code, or the permissions the App is running under.
Please, can anyone suggest what I need to do to fix this?
Thanks to #SertacAkyuz for reminding me about file system redirection - trying to access %Windir%\system32 from a 32bit program will be redirected to %Windir%\SysWow64 which doesn't contain the dns folder.
You can use the virtual alias %Windir%\Sysnative to gain access to the actual system32 folder from a 32bit application, and that works for the above case. so browsing to %Windir%\sysnative\dns allows me to enumerate the folders correctly.

Why doesn't my code find any registry keys?

I want to list USB VIDs from the registry, and I wrote the following Delphi code:
procedure FindUSBvids(VIDs: TStrings);
var
Reg1: TRegistry;
begin
Reg1 := TRegistry.Create;
try
Reg1.RootKey := HKEY_LOCAL_MACHINE;
Reg1.OpenKey('System\CurrentControlSet\Enum\USB', False);
Reg1.GetKeyNames(VIDs);
finally
Reg1.Free;
end;
end;
procedure TForm1.Button6Click(Sender: TObject);
FindUSBvids(Memo2.Lines);
end;
Unfortunately the Memo remains empty. I triple-checked the key, it exists and has a couple dozen subkeys. What am I doing wrong?
(Note: I'm not sure this is the right way to find USB VIDs, but that's not the point. It's just that I'm puzzled why the code doesn't produce any result.)
You are asking for write access to the registry key. Use OpenKeyReadOnly instead of OpenKey.
Are you running your application with elevated access rights as administrator or as a normal user.
When you are using OpenKey Delphi by default tries to access that registry key using Read and Write access.
Now on Windows XP this would be just fine but on Windows Vista and newer this can be blocked by UAC especially if you are trying to read registry contents from HKEY_LOCAL_MACHINE part because this part of the registry is protected and requires elevated privileges to be modified.
So you need either to launch your application with administrative rights or change the Access property to `KEY_READ'. I would recommend using the lather if you are only enumerating the USB devices.

Generate PDF using QuickReport from a Windows Service in Delphi

I'm writing a windows service using Delphi XE3. The service is going to read from a database, generate a pdf using quickreport 5.05.1.
I plan to generate the pdf using TQRPDFDocumentFilter.
Everything works fine in a normal VCL application, but when I implement it in a windows service the service hangs (without any exceptions) when I do a QuickRep.Prepare.
I have read that it is possible to use QuickReport in a windows service, but I do not know how. Any suggestions?
Where is the code:
procedure foo
var
pdfFilter: TQRPDFDocumentFilter;
begin
with TForm2.Create(Self) do
begin
ClientDataSet1.Open;
QuickRep1.Prepare;
pdfFilter := TQRPDFDocumentFilter.Create(GetApplicationFolder() + 'test.pdf');
try
QuickRep1.QRPrinter.ExportToFilter(pdfFilter);
finally
pdfFilter.Free;
ClientDataSet1.Close;
end;
end;
end;
Edit:
I have also tried turning off "show progress" on the QuickReport as suggested in another thread.
Writing some code to catch an exception reveals that it indeed throws one. The message is "There is no default printer currently selected".
So this leads me to believe that the local system user that the service is running under does not have any printers installed and that this is the problem.
I have resolved a similar problem (printing to a shared network printer from a Java server running as a Windows service) with these steps:
log on as the user who will run the service
install the printer
IIRC with Delphi applications, the printer name is not case sensitive (with Java it is).

Run Non-Visual GUI App from LocalSystem Service

Background
We need to run a GUI application from a Windows Service, set to Log On as Local System (and without enabling interact with desktop).
The GUI application takes one command-line parameter, performs a specific task and then self-terminates. It is a GUI app because some of its components require a parent TForm, so a console app doesn't work. There are no dialogs or any UI a user would see. In fact, it creates itself as a hidden form with no taskbar icon:
Application.Initialize;
Application.MainFormOnTaskbar := False; // <- No taskbar icon
Application.ShowMainForm := False; // <- Main form is hidden
Application.CreateForm(TForm1, Form1);
Application.Run;
It is possible that the GUI app may be launched multiple times simultaneously, each with its own command-line parameter. Since a GUI app can't be spawned directly in the Session 0 process of the service, I created an Administrator user account so the service can log on the admin user and run the GUI app as the admin user. Once I get it to work once, I will leave this user logged in so the service can quickly launch the GUI app without the login/logout overhead each time it spawns the GUI app.
What I've Done
I'm using the following code, formed from dozens of discussions on this topic, even though most of them wanted the GUI app to be seen by a logged on user.
function CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; bInherit: BOOL): BOOL; stdcall; external 'userenv.dll';
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall; external 'userenv.dll';
var
_usertoken: THandle;
_si: _STARTUPINFOW;
_pi: _PROCESS_INFORMATION;
_env: Pointer;
_sid: Cardinal;
begin
if LogonUser(PChar(Username), PChar('localhost'), PChar(Password), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, _usertoken) then
try
ZeroMemory(#_si, SizeOf(_si));
_si.cb := SizeOf(_si);
// _si.lpDesktop := 'WinSta0\Default'; // <- behaves the same with or without this
if CreateEnvironmentBlock(_env, _usertoken, False) then
try
if CreateProcessAsUser(_usertoken, nil, PChar(sCMD), nil, nil, False, CREATE_UNICODE_ENVIRONMENT, _env, nil, _si, _pi) then
begin
WaitForSingleObject(_pi.hProcess, 30000);
CloseHandle(_pi.hThread);
CloseHandle(_pi.hProcess);
end
else
_handle_error('CreateProcessAsUser() failed.');
finally
DestroyEnvironmentBlock(_env);
end
else
_handle_error('CreateEnvironmentBlock() failed.');
finally
CloseHandle(_usertoken);
end
else
_handle_error('LogonUser() failed.');
end;
The Windows Event Viewer [Security Log] shows an entry when LogonUser() is called. The following privileges appear in the log entry:
SeTcbPrivilege
SeSecurityPrivilege
SeTakeOwnershipPrivilege
SeLoadDriverPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeDebugPrivilege
SeSystemEnvironmentPrivilege
SeImpersonatePrivilege
sCmd is set to "c:\path\myapp.exe" "parameter". When sCmd was not properly set, CreateProcessAsUser() would fail with an error of 2 - The system cannot find the file specified. Once I fixed that, CreateProcessAsUser() returns True, but it never actually launches the GUI application.
Question
I'm not sure what I'm missing. I would appreciate any help with getting the service to launch the GUI app under the logged on Username/Password profile, if that's the right way to do this. Or, if there is a better way to do it, I would appreciate any direction and insight.
Thanks to David, Remy and Andy for comments. It helped me to step back and look at the issues from a fresh point-of-view. The solutions ended up being very simple.
Problem 1 - GUI Apps and "Session 0" Services Processes
A service cannot have UI elements or spawn a program that has UI elements. I thought this meant I couldn't use any GUI type controls, like TForm or TWinControl components. So I was trying to figure out how to launch a GUI program from a service (e.g., to the interactive desktop or by logging a user on and launching it to their desktop).
Turns out that as long as you don't have a dialog or some visual control that a user needs to interact with or respond to, it works perfectly fine to include GUI components in a service or an app the service spawns.
Problem 2 - "Control has no parent window"
I found one instance in my code where I created a control at runtime and didn't set its parent. Hard to track down, but fixed.
Problem 3 - External App only launched under "my" user profile
I set the service to Log On three ways, 1) as Local System, 2) as my username/password, and 3) as another admin user's username/password (with identical rights as me).
In all three instances, the return code from within the service to launch the external app indicated it successfully launched the app. However, only when the service was set to Log On using my username/password would the app actually run.
I found a information message in the system event log that said a BPL wasn't found for both of the other two instances. This was because I have a personal user path environment variable that includes an entry for the BPL directory. The other admin user and the Local System accounts do not have this. So of course the app failed to load the needed BPLs and therefore could not run.
Problem 4 - LocalSystem Access to File System
When we pushed the new code and modules to our production servers, the external app failed to properly launch and perform its task (but this time with no messages in the Windows event logs).
There are several parameters that the external app needs (too many to pass on the command line) so the service places all of the parameters into a uniquely named INI file and pass the name of the INI file to the external app. Once the external app finishes its task, it deletes the INI file.
As it turns out, the external app was launched using the Local System account, which didn't have access to the file system and therefore could not open/use the INI file. Once we granted the appropriate rights to the Local System account, it started working correctly in our production environment as well.
Everything works great now.

Indy 10 Delphi FTP Client Demo Error

I am new to Delphi and wanted to try breaking down a demo to understand the it's structure.
I am trying to get the Indy 10 Delphi FTP Client demo to run on Delphi XE2.
Whenever I run the downloaded code, I enter the FTP URL, Username, Password etc and when the FTP connects this error appears:
raised exception class $C00000005 with message 'access violation at
0x0018f90e: write of address 0x0000000'
Which I assume it means it's pointing at a null?
The debugging tool simple points at this line..
ChangeFTPDir(Sites[cbFTPAddress.ItemIndex].RootDir);
What would be the best way of removing this error (try/catch) or is there a working sample of a Delphi FTP procedure that I could have a look at?
Thanks for your time in advance,
Sophie
The procedure is as below:
procedure TfrmMain.ChangeFTPDir(NewDir: String);
begin
FLastDirStack.Add(FTP.RetrieveCurrentDir);
FTP.ChangeDir(NewDir);
DisplayFTP;
end;
I assume that the site array does contain details as the ftp does connect to the name of the stored ftp site before the error appears...
Did you use IdAllFTPListParsers ? Try it.

Resources