Jump to content

Remy Lebeau

Members
  • Content Count

    2343
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    "Gotchas" when calling from a C DLL to a Delphi DLL?

    There are only 2 other ways that I know of: a deadlock inside of the function, so it never even tries to exit. a corrupted call stack, ie the return address gets overwritten before the function tries to exit.
  2. Remy Lebeau

    "Gotchas" when calling from a C DLL to a Delphi DLL?

    The exception handler itself is coded fine (once you fix the undefined behavior of your IntToStr() implementation), it just may not catch every possible type of exception that can be thrown. It can only handle SEH exceptions. But there is no guarantee that what you are experiencing is even related to exceptions. There may not even be an exception being thrown at all.
  3. Remy Lebeau

    "Gotchas" when calling from a C DLL to a Delphi DLL?

    I would suggest writing your own test EXE that simply loads the C DLL directly and calls its DriverOpen() function. Then you can step into the DLL with the debugger to see how it calls into your DelphiDriverOpen() function, see how the parameter data gets passed back and forth, how the call stack is managed, etc. then it may be an environmental issue rather than a coding mistake. Maybe the offending machine(s) are simply using a different/newer API than what your DLLs use. Who knows. can't answer that seeing the actual code, so stepping through it with a debugger. if the exception handler is not being called, then either there is no exception being thrown at all, or it is not an SEH-based exception.
  4. Remy Lebeau

    "Gotchas" when calling from a C DLL to a Delphi DLL?

    No, it is not. And besides, your IntToStr() has undefined behavior anyway. You should get rid of that function and just use sprintf() directly in your HandleException(). But that is beside the point. That implies to me that possibly either: there is a calling convention mismatch in how DelphiDriverOpen() is declared in both languages. the Delphi DLL is corrupting the call stack. an uncaught exception is being thrown. You will have to use the debugger to verify one way or the other.
  5. Remy Lebeau

    Blogged : Delphi Package Manager RFC

    You SHOULD already be able to have per-project packages, in all versions of Delphi. The trick is to install the packages but NOT ENABLE them globally. With no project loaded, install the packages as needed, and then disable them so they don't appear in the Palettes when no project is loaded. Then, load a project, enable only the installed packages it actually needs, and close the project. Repeat as needed for other projects. Then, from now on, the IDE should load and unload packages on a per-project basis. At least, this is how it used to work years ago, I haven't tried it in recent years. Hopefully it still works.
  6. Remy Lebeau

    "Gotchas" when calling from a C DLL to a Delphi DLL?

    That would imply that the Delphi DLL is not coded properly for the Citrix driver API, since Delphi can certainly produce C-compatible DLLs. Aside from that, the only thing I see wrong in your Delphi translation is that HND should be a Pointer instead of a THandle, and pLibMgrCallTable should be a Pointer instead of a ^DWORD. However, you did not show your translation of the PVD type, or of the DriverOpen() and other DLL function declarations. Since Citrix is complaining about an invalid handle, did you debug your C and Delphi DLLs to log the value of the handle that DriverOpen() actually returns, and the value of the handle that the other DLL functions receive? Where exactly does DriverOpen() return the handle to - the 'int' return value, or in the PVD parameter?
  7. Remy Lebeau

    HELP: Using C++ .dll in Delphi

    Your translation is WAY off. DONT use String for char* parameters, use PAnsiChar instead. DONT use Integer for (D)WORD parameters, use (D)WORD instead. And your handle parameter needs to be declared as 'var' or 'out' since it is an output parameter. Try this instead: function MXEIO_E1K_Connect(szIP: PAnsiChar; wPort: WORD; dwTimeOut: DWORD; var hConnection: Integer; szPassword: PAnsiChar): Integer; stdcall; external 'MXIO.dll' name 'MXEIO_E1K_Connect'; Or this: function MXEIO_E1K_Connect(szIP: PAnsiChar; wPort: WORD; dwTimeOut: DWORD; hConnection: PInteger; szPassword: PAnsiChar): Integer; stdcall; external 'MXIO.dll' name 'MXEIO_E1K_Connect';
  8. Remy Lebeau

    HELP: Using C++ .dll in Delphi

    The DLL's documentation includes VB declarations. VB doesn't support cdecl at all, only stdcall. Also, I just found this, which clearly shows the DLL functions using CALLBACK for the calling convention. That is a preprocessor macro that maps to __stdcall.
  9. Remy Lebeau

    Request to Google Translate API

    In general, when creating a URL by hand, I suggest NOT using TIdURI.URLEncode() on the entire URL, but instead use TIdURI.PathEncode() and TIdURI.ParamsEncode() on individual components that actually need to be encoded. Also, the default encoding for TStringStream is the OS default charset, but JSON typically uses UTF-8 instead. If you know the actual charset the server uses for the response, you could hard-code it in the TStringStream constructor. But, it is generally better to just let TIdHTTP handle charset decoding of strings for you instead. Try something more like this: var http : TIdHTTP; sslIO : TIdSSLIOHandlerSocketOpenSSL; url, data : String; begin http := TIdHTTP.Create(nil); try http.HTTPOptions := http.HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent]; sslIO := TIdSSLIOHandlerSocketOpenSSL.Create(http); sslIO.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; sslIO.SSLOptions.Mode := sslmClient; sslIO.SSLOptions.VerifyMode := []; sslIO.SSLOptions.VerifyDepth := 0; http.IOHandler := sslIO; url := 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=de&tl=ru&dt=t&q=' + TIdURI.ParamsEncode('Müller'); data := http.Get(url); finally http.Free; end; end;
  10. Remy Lebeau

    Blogged : Delphi Package Manager RFC

    FreePascal already has its own Online Package Manager built right into the Lazarus IDE.
  11. Remy Lebeau

    Save tpaintbox to bitmap

    You can't, as TPaintBox is painted dynamically on an as-needed basis, so there is no persistent image to "capture". You need to change your drawing code to draw onto a TBitmap (or any arbitrary TCanvas) instead, and wrap that code into a function that you can call whenever needed. That way, when the TPaintBox needs to be painted, create a temp TBitmap, have the function draw onto it, and then draw that TBitmap onto the TPaintBox. When you want to do the "capture", create another temp TBitmap, have the function draw onto it, and then use the TBitmap as needed. This applies to both VCL and FMX, BTW.
  12. Remy Lebeau

    TIdMessageBuilderHtml add background color

    That has nothing to do with Indy, and everything to do with your particular HTML/CSS, and whether the receiver supports what you are trying (for instance, not all email readers support background images - see The Ultimate Guide to Background Images in Email ). Indy does not care about the particular content of your HTML, it gets sent as-is (other than to encode it for transmission purposes only). I will say this, though: - in your 1st case, 'url("back,png")' is wrong for an embedded image, you need to use 'url("cid:back.png")' instead since "back.png" is the Content-ID you assigned to the attachment. - in your 2nd case, the 3rd call to Html.Add() appears to be broken.
  13. Remy Lebeau

    First!

    I'm here!
  14. There is nothing wrong with using threads in general, you just have to understand WHEN and HOW to use them effectively. You can't write really high performant software without them. Especially on mobile platforms. I've been writing commercial software for 20 years as well, and have written many multi-threaded applications, just using Delphi's 'TThread' class. I don't use a version that has Embarcadero's "Parallel Processing Library" available (I would never trust it anyway, it has had too many bugs over the years!), and I don't use 3rd party threading libraries, like OmniThreadLibrary, etc (not that there is anything wrong with them, I just never got into them).
  15. Actually, since Delphi 6+, the preferred method is to use $IF with the CompilerVersion and/or RTLVersion constants, instead of using $IFDEF with the VERxxx conditionals.
  16. Remy Lebeau

    What is the fastest way to check if a file exists?

    Why is GetFileAttributes the way old-timers test file existence?
  17. Remy Lebeau

    Shellexecute cmd.exe with spaces

    And even that is not needed if you use CreateProcessElevated() instead.
  18. Remy Lebeau

    How To HTTP POST in Delphi?

    Your TIdHTTP code is all wrong for this kind of POST request. Try something more like this instead: uses ..., IdGlobalProtocols, IdHTTP, IdSSLOpenSSL; procedure TForm3.Button2Click(Sender: TObject); var SoapMsg: string; PostData, ResponseData: TStream; begin // buid up this string however you want (XML library, etc) ... SoapMsg := '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">' + ' <soapenv:Header/>' + ' <soapenv:Body>' + ' <tem:Consulta>' + ' <!--Optional:-->' + ' <tem:expresionImpresa><![CDATA[?re=LSO1306189R5&rr=GACJ940911ASA&tt=4999.99&id=e7df3047-f8de-425d-b469-37abe5b4dabb]]></tem:expresionImpresa>' + ' </tem:Consulta>' + ' </soapenv:Body>' + '</soapenv:Envelope>'; ResponseData := TMemoryStream.Create; try PostData := TStringStream.Create(SoapMsg, TEncoding.UTF8); try IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1; IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent]; IdHTTP1.Request.ContentType := 'text/xml'; IdHTTP1.Request.Charset := 'utf-8'; IdHTTP1.Request.Accept := 'text/xml'; IdHTTP1.Request.CacheControl := 'no-cache'; IdHTTP1.Request.CustomHeaders.Values['SOAPAction'] := 'http://tempuri.org/IConsultaCFDIService/Consulta'; IdHTTP1.Post('https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl', PostData, ResponseData); finally PostData.Free; end; Memo1.Lines.BeginUpdate; try Memo1.Lines.Add(Format('Response Code: %d', [IdHTTP1.ResponseCode])); Memo1.Lines.Add(Format('Response Text: %s', [IdHTTP1.ResponseText])); ResponseData.Position := 0; ReadStringsAsCharset(ResponseData, Memo1.Lines, IdHTTP1.Response.Charset); finally Memo1.Lines.EndUpdate; end; finally ResponseData.Free; end; end;
  19. Remember that a pointer-to-class-method, such as TWndMethod, is represented by the RTL's TMethod record, which contains 2 pointers - a pointer to an object instance, and a pointer to the method code. TValue.AsUInt64 fails for a TWndMethod value because TValue supports only conversions that the compiler natively supports implicitly, and you can't implicitly assign a TMethod to a UInt64 and vice versa. That also explains why the TValue.GetReferenceToRawData() approach works - it is just returning a raw pointer to the actual TControl.FWndMethod instance member, which is then dereferenced when being assigned to the local TWndMethod variable. So, no conversion occurs. Now, why TValue.AsType<TWndMethod> fails to compile, I don't know. Sounds like a bug.
  20. Remy Lebeau

    VCL Support for Per Monitor v2 and GetSystemMetrics Coming in 10.3

    The VCL has a GetParentForm() function in the Vcl.Forms unit for this very purpose.
  21. I would probably take it a step further, to avoid repeatedly indexing into the array: var Idx: integer; Rec: ^TSomeRec; // [...] Idx := CountInMyArr; SetLength(MyArr, Idx + SomeDelta); Rec := @MyArr[Idx]; Rec.SomeField := SomeValue; // and repeated for each field in TSomeRec Inc(CountInMyArr);
×