-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
That is actually incorrect in the case of TIniFile. Internally, it uses the Win32 PrivateProfile API, and if you don't specify a full path then it will use the Windows folder, not the calling process' working directory: This is not the case with TMemIniFile. Agreed.
-
Problem with ClientToScreen() on Multiple Monitors
Remy Lebeau replied to Steve Maughan's topic in VCL
Is there an error message? And you didn't answer my question - which version of Delphi are you using? Nothing in the code you have shown should be accessing any monitor-specific functionality, AFAIK. Yes. -
Problem with ClientToScreen() on Multiple Monitors
Remy Lebeau replied to Steve Maughan's topic in VCL
Which version of Delphi are you using? TControl.ClientToScreen() does not take 2 integers as input, it takes either a TPoint or a TRect. But, fixing that, the rest of the code shown works just fine for me on my 2-monitor system. ClientToScreen() returns screen coordinates, and Popup() takes screen coordinates, and screen coordinates are within the Virtual Screen, not any particular monitor. Regardless of which monitor the PaintBox is displayed on, the PopupMenu appear wherever I click on the PaintBox. So, either you are doing something else wrong that we can't see, or this is a bug in your Delphi's VCL, -
I agree, this does not sound like an Indy issue, especially since the PDFs can be opened on older iPhones without changing the Indy code. But, this does not necessarily negate the possibility that the emails might not be getting setup correctly to begin with, and perhaps newer iPhones are just less lenient on mistakes than older iPhones? Can you please show the actual code you are using? And what the raw data of the emails actually looks like? Also, are you having the same problem when sending the emails via Outlook to iPhone? If not, then I suggest you compare the raw data of Outlook's email to Indy's emails to see what is different between them.
- 6 replies
-
- emails
- attachments
-
(and 1 more)
Tagged with:
-
Try something more like this: procedure Tmain.buildrackClick(Sender: TObject); var c, r, box : Integer; RackId : string; begin //ShowMessage('draw grid'); setgridrow := -1; setgridcol := -1; box := 0; RackId := ListBox1.Items[ListBox1.ItemIndex]; with StringGrid1 do begin ColCount := 1{FixedCols} + ddata.RackClientDataSet.FieldByName('c').AsInteger; RowCount := 1{FixedRows} + ddata.RackClientDataSet.FieldByName('r').AsInteger; for c := 1{FixedCols} to ColCount - 1 do begin Cells[c, 0{FixedRows-1}] := 'Column ' + IntToStr(c); end; for r := 1{FixedRows} to RowCount - 1 do begin Cells[0{FixedCols-1}, r] := 'Row ' + IntToStr(r); for c := 1{FixedCols} to ColCount - 1 do begin Inc(box); if ddata.TubClientDataSet.Locate('Rackid;Tubid', VarArrayOf([RackId, box]), []) and (ddata.TubClientDataSet.FieldByName('id').AsString <> '') then begin Cells[c, r] := 'Bin ' + IntToStr(box) + ' ' + ddata.TubClientDataSet.FieldByName('id').AsString; if (DBEdit17.Text = RackId) and (DBEdit18.Text = IntToStr(box)) then begin setgridrow := r; setgridcol := c; //ShowMessage('cell is row ' + IntToStr(r) + ' col ' + IntToStr(c)); end; end else begin Cells[c, r] := 'Bin ' + IntToStr(box); end; end; end; DefaultColWidth := Trunc((Width-56)/ColCount); DefaultRowHeight := Trunc((Height-45)/RowCount); ColWidths[0] := 56; end; end; ... if (setgridcol <> -1) and (setgridrow <> -1) then begin //StringGrid1.Refresh; ShowMessage(IntToStr(setgridcol) + ' is col ' + IntToStr(setgridrow) + ' is row - try to set cell selected.'); //StringGrid1.SetFocus; ShowMessage('grid focused'); StringGrid1.Col := setgridcol; ShowMessage('col set'); StringGrid1.Row := setgridrow; ShowMessage('row set'); end;
-
TThread Resume Suspend deprecated (Not synchronization)
Remy Lebeau replied to Clément's topic in RTL and Delphi Object Pascal
I vote for this approach. Limiting the listener to run only when the number of connections is below a max threshold is exactly the kind of situation that semaphores are intended for. See Semaphore Objects for details. -
Trying to avoid using SetString when doing a token lookup in a TDictionary
Remy Lebeau replied to MarkShark's topic in RTL and Delphi Object Pascal
Yes. Depending on the hash algorithm used, the risk of hash collisions occurring is small, but not non-existant. In this situation, since you want strings as keys, I would probably opt to define a custom record type that holds a PChar and a length, and then use that record as the dictionary key. You would just need to provide a custom IEqualityComparer implementation to compare the keys. See https://stackoverflow.com/a/27820226/65863 as an example. -
Trying to avoid using SetString when doing a token lookup in a TDictionary
Remy Lebeau replied to MarkShark's topic in RTL and Delphi Object Pascal
Your example is checking for 4 bytes, not 8 bytes. And also, presumably @TokenStart should be FTokenStart, which is already a pointer. But, in any case, if the strings are greater than SizeOf(UInt64) in length, you are only using those first 8 bytes for the "key", so you might not end up with unique keys for different string values. -
Upload files from Delphi to PHP
Remy Lebeau replied to Luciano Veneziano's topic in Network, Cloud and Web
It should look like this: uses ..., IdMultipartFormDataStream; var PostData: TIdMultipartFormDataStream; begin PostData := TIdMultipartFormDataStream.Create; try PostData.AddFile('upfile', 'C:\path\filename'); IdHTTP.Post('https://server/UPLOAD.PHP', PostData); finally PostData.Free; end; end; -
GStack.LocalAddress is deprecated, you should be using GStack.GetLocalAddressList() instead. Indy does not currently use WifiManager, that operates at the Android Java layer, but since Indy operates at the native layer then it uses Linux APIs instead to enumerate local IPs, namely gethostname()+getaddrinfo() (there is a TODO in IdStackVCLPosix.pas to use getifaddrs() instead, or Android's NetworkInterface or WifiManager). MakeDWordIntoIPv4Address() is deprecated, use MakeUInt32IntoIPv4Address() instead. Alternatively, have a look at TIdIPAddress.IPv4(AsString) (which uses MakeUInt32IntoIPv4Address() internally). But in any case, the input value is expected to be in network byte order, aka big endian, but WifiInfo.getIpAddress() returns an IPv4 address in host byte order, which may be either little endian or big endian, depending on the device. You can use Integer.reverseBytes() to swap the IP's endian if ByteOrder.nativeOrder() is LITTLE_ENDIAN. Seems Indy's own use of MakeUInt32IntoIPv4Address() may be inconsistent, some places use host byte order, some don't. Also, WifiInfo.getIpAddress() is deprecated since Android 12. You should use LinkProperties now.
-
Possibly. Embarcadero has been playing around with High-DPI support for a few versions now, which can cause weird side effects.
-
TWSocket problem on Delphi Intraweb
Remy Lebeau replied to Baxing's topic in ICS - Internet Component Suite
I don't agree, since the failure is coming straight from the Win32 API itself. But there is definitely something fishy going on here. The only thing that makes sense to me is if maybe the window created by AllocateHWnd() was silently destroyed, but the FWinHandle variable wasn't updated to reflect that. What does IsWindow(FWinHandle) report after AllocateHWnd() returns, and when PostMessage() fails? Even if there were no message *pump* to process messages, there would still be a message *queue* (a thread's message *queue* is created the first time the thread calls any function in user32.dll) when the window is created. PostMessage() fails with error 1400 only if the provided HWND is not a valid window, not if the window is valid but no message pump is running. PostMessage() has no concept of whether a pump is running or how often, it only cares if the queue exists and is not full. And the failing code has nothing to do with IntraWeb itself, but rather with the Win32 API directly. -
On the client side, I would strongly advise you NOT to bind the TIdTCPClient and TIdHTTPProxyServer to the same local IP/Port at all. Put the destination proxy server's IP/Port in the DEST command itself, and then have the receiving server extract the values from the command, not from the connected socket. Then you can drop the TIdTCPClient connection after sending the DEST command, and even run the TIdTCPClient on a different PC if you wanted to. constructor TRemoteServer.Create(IP: string; Port: Integer); begin IdHTTPProxyServer1 := TIdHTTPProxyServer.Create(nil); IdHTTPProxyServer1.ReuseSocket := rsTrue; IdHTTPProxyServer1.DefaultPort := Port; IdHTTPProxyServer1.OnHTTPBeforeCommand := HTTPBeforeCommandHandler; var handler := IdHTTPProxyServer1.CommandHandlers.Add; handler.Command := 'DEST'; handler.HelpSuperScript := 'Sets caller as a DESTINATION for remote support (usage DEST PIN IP PORT URL)'; handler.OnCommand := DEST_Handler; if (IP <> '') and (Port <> 0) then begin Writeln('Starting server, binding to: ' + IP + '-' + Port.ToString); var bind := IdHTTPProxyServer1.Bindings.Add; bind.IP := IP; bind.Port := Port; bind.ReuseSocket := rsTrue; end else Writeln('Starting server, default binding'); IdHTTPProxyServer1.Active := True; Writeln('Server running, listening on: ' + IdHTTPProxyServer1.Bindings[0].IP + ' - ' + IdHTTPProxyServer1.Bindings[0].Port.ToString); end; procedure TRemoteServer.DEST_Handler(ASender: TIdCommand); begin Writeln(ASender.RawLine); dest_pin := ASender.Params[0]; dest_ip := ASender.Params[1]; dest_port := ASender.Params[2]; dest_url := ASender.Params[3]; Writeln('Address: ' + dest_ip + ' - ' + dest_port.ToString); end; procedure TRemoteServer.HTTPBeforeCommandHandler(AContext: TIdHTTPProxyServerContext); begin if dest_ip <> '' then begin Writeln('Command redirected to DESTINATION: ' + dest_ip + ' - ' + dest_port.ToString); var tempIO := TIdIOHandlerStack.Create(AContext.OutboundClient); tempIO.ReuseSocket := rsTrue; // tempIO.BoundIP := '10.0.2.4'; //IdHTTPProxyServer1.Bindings[0].IP; tempIO.BoundPort := 443; // IdHTTPProxyServer1.Bindings[0].Port; var tempProxy := TIdConnectThroughHttpProxy.Create(AContext.OutboundClient); tempProxy.Enabled := True; tempProxy.Host := dest_ip; tempProxy.Port := dest_port; tempIO.TransparentProxy := tempProxy; AContext.OutboundClient.IOHandler := tempIO; end; end; procedure TForm1.ConnectToRemote(Connection: string); begin HTTPProxyServer.Active := False; HTTPProxyServer.Bindings.Clear; var bind := HTTPProxyServer.Bindings.Add; bind.IP := ...; bind.Port := ...; bind.ReuseSocket := rsTrue; HTTPProxyServer.Active := True; // Tell server we are there IdTCPClient1.Host := <SERVER IP/URL>; //Connection.Split([':'])[0]; IdTCPClient1.Port := <SERVER PORT>; // Connection.Split([':'])[1].ToInteger; IdTCPClient1.Connect; try IdTCPClient1.SendCmd('DEST 4444 ' + bind.IP + ' ' + bind.Port.ToString + ' https://abc.com'); finally IdTCPClient1.Disconnect; end; end;
-
How to use tDateTimePicker for BOTH date and time
Remy Lebeau replied to A.M. Hoornweg's topic in VCL
Has that been reported as a bug yet? If not, it should be. -
Try something like this: procedure update_toc(const docx_file: string); var word, doc: Variant; begin word := CreateOleObject('Word.Application'); doc := word.Documents.Open(WideString(docx_file)); doc.TablesOfContents.Item(1).Update; doc.Close(-1); word.Quit; end;
-
My usual QP credentials are not working right now.
-
How to use tDateTimePicker for BOTH date and time
Remy Lebeau replied to A.M. Hoornweg's topic in VCL
That must be a new feature added in 11.0 Alexandria, because in 10.4 Sydney the only options available were still dtkDate and dtkTime. In which case, I would expect there to be a new and easier way to get the full TDateTime value without resorting to parsing the display text manually. -
It is not just the load balancer that is having issues. For example, trying to access several pages today, I'm running into a new kind of error:
-
Transfer a file from client to server (Delphi XE)
Remy Lebeau replied to MrCamarium's topic in Network, Cloud and Web
You can use the connection's OnWork events for that purpose. Just be aware that they are fired in the context of the thread that is performing the transfer, so if that is not the main UI thread then you will have to synchronize your UI updates with the main thread. https://www.indyproject.org/2021/02/10/links-to-old-indy-website-pages-are-currently-broken/ https://web.archive.org/web/20200925081341/http://ww2.indyproject.org/Sockets/Docs/Indy10Installation.EN.aspx That is a build script for C++Builder (hence the C in the filename), not for Delphi. Indy stopped using build scripts for Delphi after D2009. For Delphi, you can just open the project files directly in the IDE and use the Compile and Install options in the Project Manager. Of course, because 1) you didn't remove the old version from the IDE, and 2) the build script only compiles the library binaries, but it does not install them into the IDE. You have to do that step manually. Never use relative paths, always use absolute paths. -
Transfer a file from client to server (Delphi XE)
Remy Lebeau replied to MrCamarium's topic in Network, Cloud and Web
That is an extremely old version of Indy, you should upgrade to the latest version, which is 10.6.2. Even if you can't upgrade your IDE. -
Transfer a file from client to server (Delphi XE)
Remy Lebeau replied to MrCamarium's topic in Network, Cloud and Web
OK, thanks. The TIdTCPServer.OnExecute event is fired in an endless loop for the lifetime of the TCP connection. The event doesn't care what data is transmitted. That is the responsibility of the code inside of the event to deal with as needed. That doesn't really matter in this case. ReadStream() will handle those chunks internally. The code's use of Write() is sending the file size followed by the file data. Then the code's use of ReadStream() is reading the file size and then reading the file data up to that size. -
Transfer a file from client to server (Delphi XE)
Remy Lebeau replied to MrCamarium's topic in Network, Cloud and Web
What errors, exactly? Please be more specific. And, are you really using Delphi XE? That is 12 years old. Are you, at least, using an up-to-date version of Indy? Or, are you are using a 12-year-old version? The code to transfer the file looks fine to me, so you are just going to have to debug deeper. That zip file contains the same client code you originally posted. It does not include the changes I suggested for the client. -
Transfer a file from client to server (Delphi XE)
Remy Lebeau replied to MrCamarium's topic in Network, Cloud and Web
You are leaking the TFileStream object. You need to Free() it when you are done using it. You should wrap the call to Write() in a try..finally block for that, in case Write() raises an exception, eg: procedure TForm1.Button3Click(Sender: TObject); var TFLFileOut: TFileStream; begin TFLFileOut := TFileStream.Create(ToDownload.Text, fmOpenRead or fmShareDenyWrite); try Client.IOHandler.Write(TFLFileOut, 0, true); finally TFLFileOut.Free; end; end; Likewise, you should use try..finally here too, to ensure the TFileStream is Free()'d even if an exception is raised. procedure TForm1.ServerExecute(AContext: TIdContext); var TFSFileIn: TFileStream; begin Label1.Caption := 'Arriva qualcosa...'; TFSFileIn := TFileStream.Create(Edit1.Text, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; But, more importantly, TIdTCPServer is a multi-threaded component. Its OnExecute event is fired in the context of a worker thread, not the main UI thread. As such, accessing UI controls, such as your TLabel an TEdit controls, is NOT thread-safe. You MUST synchronize with the main UI thread when accessing them, eg: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; Your calls to Write() and ReadStream() are matched up properly, so I cannot see a reason why the received file would be empty, provided that Write() and ReadStream() are actually being called. Did you verify that with your debugger? -
That code pre-dates Delphi's shift to Unicode in D2009. But vtWideString and vtPWChar did exist prior to that shift. That code simply does not support Unicode strings at all.
-
TBitmap to TBytes for ESC/POS Thermal Printer
Remy Lebeau replied to at3s's topic in RTL and Delphi Object Pascal
BytesOf() for a (Wide|Unicode)String is just a wrapper for TEncoding.Default.GetBytes(), eg: SND := TEncoding.Default.GetBytes(AValue); Note that TEncoding.Default is TEncoding.ANSI on Windows, but is TEncoding.UTF8 on other platforms.