I have the code:
procedure TfrmMain.btnSendClick(Sender: TObject);
var
aMail: TJclEMail;
begin
aMail := TJclEMail.Create;
Screen.Cursor := crHourGlass;
try
aMail.Recipients.Add('service#blabla.com');
aMail.Subject := '[IMPORTANT] blablba';
aMail.Body := 'text text text text';
aMail.Send(True);
finally
Screen.Cursor := crDefault;
aMail.Free;
end;
end;
This throws: MAPI Error: (2) "General MAPI failure"
Any idea?
ps:
OS Windows 7
Outlook 2010
Delphi 2007
I have the same as you, just wrapped inside a class and it is working.
I use to check if MAPI is OK at the first time I execute Send():
function TMAPIPrerequisites.IsClientAvailable: Boolean;
var
SimpleMAPI: TJclSimpleMapi;
begin
SimpleMAPI := TJclSimpleMapi.Create;
try
Result := SimpleMAPI.AnyClientInstalled;
finally
SimpleMAPI.Free;
end;
end;
function TMAPIPrerequisites.IsMapiAvailable: Boolean;
var
SimpleMAPI: TJclSimpleMapi;
begin
SimpleMAPI := TJclSimpleMapi.Create;
try
Result := SimpleMAPI.SimpleMapiInstalled;
finally
SimpleMAPI.Free;
end;
end;
My problem was that my Jedi library wasnt up to date. I search into jedi repository and JclMapi has change in Tue Dec 27 (Mantis 5748: JclMapi incompatibilities with 64-bit.)
Download this changes, re-compile pkg and now works perfectly!
Thank you anyway!!
The above code works fine IF email client is not already running.
After struggling with same problem i found that the MAPI client has to run in same user context as the MAPI server (e-mail client - Thunderbird in my case).
However, if calling from an app started with administrator privileges (for example an app running in the debugger) then the MAPI calls would fail with error code 2. If both caller and email client are running as admin then everything works (but who's crazy enough to run e-mail client as admin these days?).
Related
I migrated a Datasnap server to XE 10.1 Berlin and now I get an error on the server when I invoke a servermethod with OUT parameters.
Object
TBtwlControlePar=class
xInDoc,
xHandmatig,
xStatus,
xVerwacht,
xAantal,
xVerwerkt,
xOnVerwerkt,
xOnverwerktInDocument,
xTotaalCustoms :Integer;
end;
function TPWAdminMethods.DOC_BTWAH_Get2(pPeriode, pMaand, pSort,pSelop,pSelOntvangen,pSelToegewezen,pSelVerwerkt: integer; pSel: string; out pControlePar: TBTWLControlePar): TResult;
ServerMethod
tmpM := TPWAdminMethodsClient.Create (DMForm.DSConnection.DBXConnection, false);
Client
FreeAndNil( fControlePar );
tmpResult := tmpM.DOC_VATLH_Get2(Jaar,sort,SelOp,SelOntvangen,SelToegewezen,SelVerwerkt,fSelection,fControlePar);
When this method is fired the server gives an error on this last line
procedure TDSMethod.Invoke(MethodInstance: TObject;
MethodValues: TDSMethodValues);
var
RContext: TRttiContext;
RType: TRttiType;
Params: TArrayOfTValue;
begin
Params := MethodValues.GetValues;
RType := RContext.GetType(MethodInstance.ClassType);
MethodValues.ReturnValue := RType.GetMethod(FMethodInfoHeader.NameFld.ToString).Invoke(MethodInstance, Params);
end;
Is it impossible to use out parameters in Delphi Berling Datasnap without the use of DBXJson?
This error message and the issue has been logged on Embarcadero's Quality Portal as RSP-14895. This was on 16May16 by someone else. That person stated "XE10 is OK".
Today (14Jun16) I added another test project to the issue. My test project is for the case of a VAR parameter. I have also provided a screenshot of the test project in action. My tests work on XE6 but fail on 10.1 Berlin.
I can't use DataSnap until this issue is fixed.
Please vote up the issue.
I wrote a program using IdHTTP and IdFTP but I have a problem. I wrote it on windows XP 32 bit (using Delphi XE4) and the exe file (Project1.exe) works fine. When I try to open it on windows 7 64 bit, the computer gives me an error.
Picture:
It means "You cannot acces to the path or the specified file. Maybe you don't have enough permissions". I've never seen this error before. Here you can see a picture of the folder with source code.
How can I solve my problem?
Here's the code:
function downloadSrc(var aUrl:ansiString):ansiString;
begin
with tIdHttp.create(nil) do begin //Create Indy http object
request.userAgent:=INET_USERAGENT; //Custom user agent string
redirectMaximum:=INET_REDIRECT_MAX; //Maximum redirects
handleRedirects:=INET_REDIRECT_MAX<>0; //Handle redirects
readTimeOut:=INET_TIMEOUT_SECS*1000; //Read timeout msec
try //Catch errors
result:=get(aUrl); //Do the request
if url.port='80' then url.port:=''; //Remove port 80 from final URL
aUrl:=url.getFullURI //Return final URL
except result:='error' end; //Return an error message if failed
free //Free the http object
end
end;
procedure TForm1.FormCreate(Sender: TObject);
var i:integer;
begin
if not(DirectoryExists('C:\mk7vrlist')) then
begin
CreateDir('C:\mk7vrlist');
end;
ComboBox1.Items.BeginUpdate;
for i := 0 to 59 do
begin
ComboBox1.AddItem(IntToStr(40000+i*1000), nil);
end;
ComboBox1.AddItem('99999', nil);
ComboBox1.Items.EndUpdate;
end;
procedure TForm1.Label5Click(Sender: TObject);
begin
ShellExecute(self.WindowHandle,'open',PChar('http://www.mk7vrlist.altervista.org'),nil,nil,SW_SHOWNORMAL);
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
var s:ansiString;
begin
IdFTP1.Host:= 'mk7vrlist.altervista.org';
IdFTP1.Username:='mk7vrlist';
IdFTP1.Password:=pass;
IdFTP1.Connect;
s:='http://www.mk7vrlist.altervista.org/databases/test.txt';
Memo1.Lines.Add(Edit1.Text+':'+ComboBox1.Text+':'+Edit2.Text);
Memo1.Lines.Add(downloadSrc(s));
Memo1.Lines.SaveToFile('C:\mk7vrlist\test.txt');
IdFTP1.ChangeDir('databases/');
IdFTP1.Put('C:\mk7vrlist\test.txt');
IdFTP1.Quit;
IdFTP1.Disconnect;
Label10.Visible:=True;
Beep;
end;
Assuming your account has administrative rights, right click on your program's icon, and invoke 'run as administrator' - you will get prompted/warned - click yes.
I don't believe the problem is 32->64 bit, but going from XP to Win 7, which by default is more particular about access.
You can set up a shortcut configured always to run it as admin, to avoid the right click step, but you will still get prompted/warned.
CreateDir('C:\mk7vrlist)
Normal users do not have that kind of access to c:\
Do something like this instead (pseudo code):
CreateDir('%temp%\mk7vrlist)
I have built the worlds dumbest and most simple SOAP server, in about 3 clicks, in visual studio. The exact steps in visual studio 2010: First create a new project as a web application, Then add a new item of type web service. (See accepted answer here for picture.) That soap server service Service1 has a simple method GetData:
A snippet from clientService1.pas, created using WSDL importer...
IService1 = interface(IInvokable)
['{967498E8-4F67-AAA5-A38F-F74D8C7E346A}']
function GetData(const value: Integer): string; stdcall;
function GetDataUsingDataContract(const composite: CompositeType2): CompositeType2; stdcall;
end;
When I try to run this method, like this:
procedure TForm3.Button1Click(Sender: TObject);
var
rio : THTTPRIO;
sv:IService1;
addr : string;
data : string;
begin
//addr := '....'; // url from visual studio 2010 live debug instance.
rio := THTTPRIO.Create(nil);
sv := GetIService1( true, addr, rio );
try
data := sv.GetData( 0);
Button1.Caption := data;
finally
sv := nil;
rio.Free;
end;
end;
The error I get is this:
ESOAPHTTPException:
The handle is in the wrong state for the requested operation -
URL:http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/ -
SOAPAction:http://tempuri.org/IService1/GetData'.
The URL works fine when I paste the url above into a web browser, so the usual answer that the SOAP code in Delphi has the tendency to not notice an HTTP failure, does not seem likely. Rather it seems that I am either (a) experiencing breakage in WinInet (known to happen in some versions of windows), or (b) doing something wrong?
It seems to me that anybody who has visual studio and delphi both installed, should be able to try to get the dummy starter Soap server in Visual Studio talking to the soap client in Delphi, without any effort at all. But I can not figure out the simplest things.
At one time there was a discussion about the error in a conversation now long since deleted from Embarcadero forums, by Bruneau Babet, an embarcadero staffer.
Bruno said:
Hello,
I've posted a patched version of SOAPHTTPTrans.pas that contains a fix
for this issue here:
[forum link redacted, it didn't work anymore anyways, the post is gone]
You may still override the event as described in the C++Builder
section referred; or, much simpler, at least for Delphi users, simply
add the updated SOAPHTTPTrans.pas to your app's project. Let us know
if that does not work for you.
Cheers,
Bruneau
You can get the repair and the notes about it in its original forum formatting from the following pastebin link and on bitbucket so you don't have to extract the file from the surrounding text.
Warren Update 2016: I have been informed by someone who tried to use the fix on Delphi XE that this fix does NOT work for them in Delphi XE. Any further updates to the code in bitbucket that resolve the remaining bugs would be appreciated.
I ran into the The handle is in the wrong state for the requested operation issue in November 2018 using Delphi Tokyo 10.2.3, then looked at the code patch in the pastebin link under Arjen's answer.
That code is very old and the test code no longer works (SOAP service unavailable). Also, it is unclear from Bruneau's code what he patched exactly.
Comparing that source and the one from my Delphi version it seems that these are the (two) required modifications in the HandleWinInetError procedure ('PATCH HERE'):
function THTTPReqResp.HandleWinInetError(LastError: DWord;
Request: HINTERNET;
RaiseError: Boolean): DWord;
function CallInternetErrorDlg: DWord;
var
P: Pointer;
begin
Result := InternetErrorDlg(GetDesktopWindow(), Request, LastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
{ After selecting client certificate send request again,
Note: InternetErrorDlg always returns ERROR_SUCCESS when called with
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED }
if LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
Result := ERROR_INTERNET_FORCE_RETRY;
end;
const
{ Missing from our WinInet currently }
INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;
var
Flags, FlagsLen, DWCert, DWCertLen: DWord;
ClientCertInfo: IClientCertInfo;
CertSerialNum: string;
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
hStore: HCERTSTORE;
CertContext: PCERT_CONTEXT;
{$ENDIF}
begin
{ Dispatch to custom handler, if there's one }
if Assigned(FOnWinInetError) then
Result := FOnWinInetError(LastError, Request)
else
begin
Result := ERROR_INTERNET_FORCE_RETRY;
{ Handle INVALID_CA discreetly }
if (LastError = ERROR_INTERNET_INVALID_CA) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
else if (LastError = ERROR_INTERNET_SEC_CERT_REV_FAILED) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_REVOCATION;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and
Supports(Self, IClientCertInfo, ClientCertInfo) and
(ClientCertInfo.GetCertSerialNumber <> '') then
begin
CertSerialNum := ClientCertInfo.GetCertSerialNumber();
hStore := ClientCertInfo.GetCertStore();
if hStore = nil then
begin
hStore := CertOpenSystemStore(0, PChar('MY'));
ClientCertInfo.SetCertStore(hStore);
end;
CertContext := FindCertWithSerialNumber(hStore, CertSerialNum);
if CertContext <> nil then
begin
ClientCertInfo.SetCertContext(CertContext);
InternetSetOption(Request, INTERNET_OPTION_CLIENT_CERT_CONTEXT,
CertContext, SizeOf(CERT_CONTEXT));
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end
{$ENDIF}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and (soPickFirstClientCertificate in InvokeOptions) then
begin
{ This instructs WinInet to pick the first (a random?) client cerficate }
DWCertLen := SizeOf(DWCert);
DWCert := 0;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
Pointer(#DWCert), DWCertLen);
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end;
end;
Note that the RaiseError procedure parameter was not even used before this patch ;-)
Here is some test code using the SOAP service from NOAA's National Digital Forecast Database (NDFD) SOAP Web Service:
Uses SOAP.SOAPHTTPTrans;
const Request2 =
'<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">' +
' <soapenv:Header/>' +
' <soapenv:Body>' +
' <ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
' <latitude xsi:type="xsd:decimal">38.9936</latitude>' +
' <longitude xsi:type="xsd:decimal">-77.0224</longitude>' +
' <startDate xsi:type="xsd:date">%tomorrow%</startDate>' +
' <numDays xsi:type="xsd:integer">5</numDays>' +
' <Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">e</Unit>' +
' <format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">12 hourly</format>' +
' </ndf:NDFDgenByDay>' +
' </soapenv:Body>' +
'</soapenv:Envelope>';
const URL2= 'https://graphical.weather.gov:443/xml/SOAP_server/ndfdXMLserver.php';
procedure TFrmHandleWinINetError.Button1Click(Sender: TObject);
var
RR: THTTPReqResp;
Response: TMemoryStream;
U8: UTF8String;
begin
RR := THTTPReqResp.Create(nil);
try
try
RR.URL := URL2;
RR.UseUTF8InHeader := True;
RR.SoapAction := 'NDFDgenByDay';
Response := TMemoryStream.Create;
RR.Execute(Request2, Response);
SetLength(U8, Response.Size);
Response.Position := 0;
Response.Read(U8[1], Length(U8));
ShowMessage(String(U8));
except
on E:Exception do ShowMessage('ERROR CAUGHT: ' + e.message);
end;
finally
Response.Free;
RR.Free;
end;
end;
end;
Without the patch errors in the tail end of the URL are caught, but errors in the domain name just trigger an empty error message.
With the patch those are also caught.
I have a reported the issue in the RAD Studio Quality Portal under number RSP-21862
Use at your own risk and please report any additional findings.
Addition: The issue was fixed in Dec 2018 in Delphi 10.3 Rio and the Quality Portal issue was closed with the following remark:
In RAD Studio 10.3 the implementation of THTTPReqResp was changed and replaced with THTTPClient. So, this issue no longer applies.
I have not verified this.
Does anybody know why the following code does not work with Excel 2010 (Home and Small Business Office Edition) ¿?
procedure TForm1.Button1Click(Sender: TObject);
var
rango : OleVariant;
ExcelObject : TExcelApplication;
ExcelWorksheet : TExcelWorksheet;
LCID : integer;
begin
try
ExcelObject := TExcelApplication.Create (self);
LCID := LOCALE_USER_DEFAULT;
ExcelObject.Workbooks.Add(EmptyParam, LCID);
ExcelWorksheet := TExcelWorksheet.Create(ExcelObject);
ExcelWorksheet.ConnectTo(ExcelObject.Worksheets.Item [1] as _Worksheet);
rango := ExcelWorksheet.Range['B2','B2'];
rango.Font.size := 16;
rango.Font.Bold := True;
rango.Value2 := 'test';
ExcelObject.Visible[lcid] := true;
except
on e: exception do
showmessage(e.message);
end;
end;
A "Not registered class" exception is shown while adding a workbook: "ExcelObject.Workbooks.Add(EmptyParam, LCID);"
This works fine with Office 2010 Proffesional Edition (and older Office Editions) but not with Home and Small Business Edition 2010 Edition.
I know this is really late but I've been fighting with this same error the last two days and finally figured it out (I think). The error is misleading due to crappy error handling in the component.
The clue I had was that it worked perfectly in a different test application on the same machine - so it wasn't a class registration issue.
I get the error (in several places) if I don't have things connected properly. In your case you probably need to do the CONNECT.
E.g.
ExcelObject := TExcelApplication.Create (self);
ExcelObject.Connect;
I've also seen this if you forget to do a ConnectTo call to connect the interfaces together.
E.g.
XlWorkBook.ConnectTo(XlApp.ActiveWorkbook);
Hope this helps someone else.
To detect and prevent shutdown the computer I use very simple program. It has only one form and one private procedure like below:
TForm3 = class(TForm)
private
procedure WMQueryEndSession(var Msg : TWMQueryEndSession) ;
message WM_QueryEndSession;
end;
and the implementation
procedure TForm3.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
Msg.Result := 0; //so I don't want to shutdown while my program is running
end;
I compiled it Delphi 5 and Delphi 2010. Both of them detect shutdown. But when I compiled in Delphi 2010; after preventing shutdown my program closes. (PC doesn't shutdown)
How do I get the same result from both of them?
EDIT: changed to intercept WM_ENDSESSION instead of WM_QUERYENDSESSION.
As you cannot directly change the behaviour of TApplication, you can install a TApplication message hook instead that neutralizes the WM_ENDSESSION message.
Installing such a hook is quite simple, you only have to add a method similar to the following to your mainform and register the hook in FormCreate.
function TForm25.HookEndSession(var Message: TMessage): Boolean;
begin
result := false;
if Message.Msg = WM_ENDSESSION then begin
Message.Result := 0;
result := true;
end;
end;
procedure TForm25.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(HookEndSession);
end;
I usually run "shutdown -a" command. You can do the same from your code to interrupt Windows from shutdown.
Regards
This looks like a bug in Delphi. I suggest you to post this on Quality Central.
Edit: Here's an approach that doesn't work. Thanks
Procedure TMyForm.FormClose(Sender: TObject; Var Action: TCloseAction);
Begin
Action := caNone; //The form is not allowed to close, so nothing happens.
End; // Note: the OP says he tried this, doesn't help. See the comments.
Are you testing on the same OS? There are some application shutdown changes in Vista. Read this: Application Shutdown Changes in Windows Vista
If you are testing on the same OS, maybe Delphi 2010 handles WM_ENDSESSION messages in a different way. In Delphi 7, WM_ENDSESSION message are handled in Application.WndProc.
In all versions should you not be using the FormCloseQuery event?
procedure TForm3.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
Canclose := Not StillDoingImportantStuff;
end;
Oops - just read comments to "this does not work" :( Is win 7 different?
In all my apps this gets called if windows is trying to shut down...
ShutdownGuard is built with Delphi and it's open source, you can download it tweak it for your needs