Jump to content

w0wbagger

Members
  • Content Count

    16
  • Joined

  • Last visited

Community Reputation

0 Neutral

Technical Information

  • Delphi-Version
    Delphi 11 Alexandria
  1. Understood. I'll take a look at ICSSnippets, which should get me to where I need to be. Thanks for your help. I'll try not to bother you again. FWIW, Chat-GPT is quite helpful in converting Pascal code to C++, for any other C++ programmers trying to make sense of Pascal code. I may even use it to convert some of the new sample code to C++ to include in a future release, if you think that would be helpful (after testing it fully, of course).
  2. Thank you, Angus. I'll unzip the 9.1 distribution and take a look at the ICSSnippets there. I thought the preferred method was to use non-blocking Async mode, so I've been trying to do that everywhere I use ICS components. Is there any downside to using Sync mode for a low-volume application?
  3. Thank you, Angus. I find it difficult to understand Pascal code, but I did what you said and I now have something that seems to be working. I pretty much directly translated, as best I could, the code from OverbyteIcsHttpRestTst.PAS. I don't think OverbyteIcsSnippets is part of what is shipped with 8.70? (Spent hours last night trying to install 9.1 on C++ builder, but was unable to get it to work). HOWEVER, I see in the OverbyteIcsHttpRestTst.PAS file that you have defined an Async Flag in the call to RestRequest. I have defined a function RESTClientRequestDone, and assigned it to RESTClient->OnRestRequestDone.. If I set Async to false, I get an immediate response to my RestRequest as 202 (file accepted), and then OnRestRequestDone fires and I can get a ton of good information about the request. This is true if I deliberately send the wrong API or an incorrect URL. The ErrCode is correct in that case and it catches the raw error data if something went awry. If I set Async to true, however, it fails with a Status code of 0, which as I understand it, is indeterminate. OnRestRequestDone still fires, but I get an HTTP 0. In both cases (Async true OR false), RESTClientRequestDone fires, but only in the non-Async version does it give me proper values. The only difference from "it works!" to "it doesn't work!" is the Async flag that I set in the call to RestRequest (see below). I just can't understand from the Pascal source what I might be doing incorrectly. It seems to work perfectly with Async = false, so I guess I can just run with that, but I would like to understand why Async mode blows up. Thanks for any light you can shed on this. Code follows: void __fastcall TfrmCAD::RESTClientRequestDone(TObject *Sender, THttpRequest RqType, WORD ErrCode) { TSslHttpRest *restClient = dynamic_cast<TSslHttpRest*>(Sender); if (restClient == nullptr) return; if (ErrCode != 0) { memoStatus->Lines->Add("Request failed: Error: " + restClient->RequestDoneErrorStr + " - " + IntToStr(restClient->StatusCode) + " " + restClient->ReasonPhrase); return; } memoStatus->Lines->Add("Request done, StatusCode " + IntToStr(restClient->StatusCode)); if (restClient->ContentType.Pos("text/") > 0 || restClient->ContentType.Pos("xml") > 0 || restClient->ContentType.Pos("json") > 0 || restClient->ContentType.Pos("java") > 0) { memoStatus->Lines->Add(String("Raw Response:"+restClient->ResponseRaw)); } else { memoStatus->Lines->Add("<Non-textual content received: " + restClient->ContentType + ">"); } // Clean up delete restClient; } //--------------------------------------------------------------------------- // Function to send an XML file to an API using ICS TSSlHttpRest void TfrmCAD::SendXMLFileToAPI(const String &xmlFileName, String& APIURL, String& APIKey) { if (!FileExists(xmlFileName)) { ShowMessage("File does not exist: " + xmlFileName); return; } // Set up the URL and SSL options TSslHttpRest *RESTClient = new TSslHttpRest( this ); RESTClient->OnRestRequestDone = &RESTClientRequestDone; RESTClient->URL = APIURL; RESTClient->SslCliSecurity = sslCliSecTls12; RESTClient->ContentTypePost = "application/xml"; // Add the API key to the request headers if (!chkSendEmptyHeader->Checked) { // I do this to test that errors are detected and reported correctly - this removes the api-key to test "not authorized". RESTClient->ExtraHeaders->Add("x-api-key: "+APIKey); } // Load the XML file into a string and start the asynchronous POST request int StatusCode; TFileStream *fileStream = new TFileStream(xmlFileName, fmOpenRead | fmShareDenyWrite); try { // Simplified approach, adjust accordingly RESTClient->SendStream = fileStream; StatusCode = RESTClient->RestRequest(httpPOST, APIURL, true, ""); // Works perfectly if Async = false, fails if Async = true; memoStatus->Lines->Add("ASync REST Request Started, StatusCode = "+IntToStr(StatusCode)); } catch (const Exception &e) { ShowMessage("Error preparing request: " + e.Message); } delete fileStream; } //--------------------------------------------------------------------------- void __fastcall TfrmCAD::btnSendXMLClick(TObject *Sender) { String xmlFileName = btnLoadXML->Text; if (!xmlFileName.IsEmpty()) { String apiKey = txtAPIKey->Text; String apiURL = txtAPIURL->Text; SendXMLFileToAPI(xmlFileName, apiURL, apiKey); } else { ShowMessage("No file selected."); } }
  4. I've been using ICS for more than 15 years but have never used the RESTful or HTTP components (always just FTP), but finally have to use it. I'm trying not to use Indy, but installing and learning how to use ICSin C++ is tough (I don't know Pascal). So apologies if I ask some stupid questions here. There were a *lot* of problems trying to use the v8.7 components (had to comment out a lot of lines from OverbyteIcsWinCrypt.hpp, because the compiler generated pretty bad .hpp files, I guess), but I couldn't get 9.1 to install in C++ Builder, so sticking with the older version for now. I've written code to send an XML stream to an API site, and having issues with the status returned. If I understand how this all works, then when I send my POST, my program should continue doing things until the REST server responds with some message, either "Bad Request", or "Unauthorized", or "200 - everything is good with what you sent" or other documented response. But it seems that what actually happens is that once the data is sent, whether good or bad, RestClientRequestDone is fired immediately with ErrCode = 0, and says it was completed successfully. However, if there was an error, it does the above (says it was successful), but then the catch at the bottom traps the error returned by the API server ("Not Authorized", or "Bad Request"). Do I misunderstand when RestClientRequestDone fires? Does it fire before hearing anything back from the API Server? If I want to wait until that happens, what event should I be trapping? Thanks in advance for your help (and your patience!) Here's my pretty simple code: // I believe this should fire after the file/apikey have been sent, and the API server responds void __fastcall TfrmCAD::RestClientRequestDone(TObject *Sender, THttpRequest RqType, WORD ErrCode) { GRequestCompleted = true; if (ErrCode != 0) { ShowMessage("Error during HTTP request: " + IntToStr(ErrCode)); } else { ShowMessage("Request completed successfully.\nResponse: " + GResponseData); } } //--------------------------------------------------------------------------- // Function to send an XML file to an API using ICS TSslHttpRest void TfrmCAD::SendXMLFileToAPI(const String &xmlFileName) { if (!FileExists(xmlFileName)) { ShowMessage("File does not exist: " + xmlFileName); return; } // Prepare the HTTP client TSslHttpRest *RESTClient = new TSslHttpRest( this ); RESTClient->OnRestRequestDone = &RestClientRequestDone; RESTClient->URL = "APIURLHIDDEN"; // Load the XML file into a stream TFileStream *fileStream = new TFileStream(xmlFileName, fmOpenRead | fmShareDenyWrite); try { // Simplified approach, adjust accordingly RESTClient->SendStream = fileStream; RESTClient->ExtraHeaders->Add("x-api-key: APIKEYREDACTED"); GRequestCompleted = false; RESTClient->Post(); // Wait for the request to complete while (!GRequestCompleted) { Application->ProcessMessages(); } } catch (const Exception &e) { ShowMessage("Error sending file: " + e.Message); } // Clean up delete RESTClient; delete fileStream; }
  5. w0wbagger

    ICS V9.1 announced

    I'm going to add what I've found here. The IcsVCLCBNewRun.cpp currently includes a #pragma link "IcsCommonCB110Run.a" and a #pragma link "IcsCommonCB110Run.lib" (I think?) these should be changed to "IcsCommonCBNewRun". IcsVCLCBNewDesign.cbproj has "IcsCommonCB110Run.bpi" under "Requires". I'm assuming that this should be removed and replaced with "IcsCommonCBNewRun.bpi". IcsVCLCBNewDesign.cbproj also has "IcsVCLCB110Run.bpi" under "Requires". I'm assuming also that his should also be removed and replaced with "IcsVCLCBNewRun.bpi" Made these changes but it still doesn't work. There are a lot of references to 110 in the various project files (vs 22.0). When I install the components in "IcsCommonCBNewDesign", no component tab gets generated, but if I look at the components from the "Components->Install Packages" screen, I see them all there. However, when I install the components from "IcsVCLCBNewDesign", it says they're installed, but there are no components showing when I click on the "Components" button from the "Components->Install Packages" screen when highlighting the VCL Design-Time Package. I'm at a bit of a loss, now.
  6. w0wbagger

    ICS V9.1 announced

    If I figure it out, I'm happy to e-mail any project file changes. I notice the difference between 8.xx installer and 9.1 installer is that the .pas files aren't included in the C++ project, and since it never opens them to compile them, (I believe) it doesn't create the .hpp files. The project file only includes the .dcr files. Again, I know nothing about the Pascal personality, so I'm going to just try adding the .PAS files to their respective projects and see if that works.
  7. w0wbagger

    ICS V9.1 announced

    Ah, I see that GetIt only installs ICS for the Delphi personality. They don't show up in the C++ Builder personality. That's new. The last time I used GetIt to install the components, they did show up in C++. Will try to figure out the manual install. Edit: I'm very unfamiliar with the Pascal personality. My understanding is that when you compile a Pascal file in C++ Builder, it automatically generates the .hpp file. Is the option not set in the project?
  8. w0wbagger

    ICS V9.1 announced

    This looks great, if I can get it working. Thank you, Angus. We use C++ Builder (Alexandria). GetIt installed everything fine, but I couldn't find the .hpp file for C++ Builder. Do they get created, or do I have to install manually? Thanks, Ian
  9. I have this same problem in C++ Builder. No idea what might be causing it. Restarting the IDE seems to solve it.
  10. Hey, thanks, Fred. I appreciate the original note, *and* the update. Our plan is just to use this inhouse to connect with our accounting software (if I can get it working).
  11. Thanks, Brian. I found the link and was able to enter my 11.2 serial number to get access to the professional version (I want to test the Quickbooks connector). Appreciate your help! Ian
  12. These components do not show up in GetIt. Are they not included with 11.2 Enterprise? If they are, how do I access them? Thanks, Ian
  13. I've used GetIt to install the components on RAD Studio 10.4.2, and am getting an error when I try to compile my app - I'm bummed, because it's infinitely easier than getting it to install manually. When I install manually (which always takes me ages, since files don't seem to go where they're needed), I don't get the same error although ICS seems to have some conflicts (usually in #defines) with DevExpress components. At any rate, when I use GetIt I'm getting an error in OverybteicsUtils.hpp as follows: [bcc32c Error] OverbyteIcsUtils.hpp(333): expected unqualified-id [bcc32c Error] OverbyteIcsUtils.hpp(334): expected unqualified-id . . . [bcc32c Error] OverbyteIcsUtils.hpp(399): expected unqualified-id [bcc32c Error] OverbyteIcsUtils.hpp(400): expected unqualified-id Every one of these lines look like this: static const System::Int8 CSIDL_DESKTOP = System::Int8(0x0); Any idea what the issue might be? Thanks, Ian
  14. Thanks Francois, I know what the EEFFACE error is. I just don't understand why it's suddenly happening with nothing else changing but the upgrade to 4.10.1.
  15. Hey folks, we've been using the ICS components on C++ Builder (well, specifically FTPClient) since it was C++ Builder 6. We've managed to upgrade each time until 10.4.0 (10.4.1, now) and 8.6.5. Suddenly, a module that compiled with no issues in the past is crashing at the Form Creation stage, and it's definitely due to the FTPClient component. If I remove it, it runs (although doesn't do much). Put it back, and fails with an EEFACE error at creation (can't even debug it - it never gets to OnFormCreate(). Has anyone else had this problem? The only thing that has changes is the compiler version and the ICS version (it ran fine on 10.3) Thanks in advance for any guidance or advice you might have.
×