Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Wow64EnableWow64FsRedirection

    Per the documentation, Wow64EnableWow64FsRedirection() is deprecated, you should be using Wow64DisableWow64FsRedirection() and Wow64RevertWow64FsRedirection() instead.
  2. Did you read the documentation? https://docwiki.embarcadero.com/Libraries/en/Xml.XMLDoc.TXMLDocument You are creating the TXMLDocument without an Owner, so it behaves like an interfaced object, but you are not treating it as an interfaced object. You need to change your pMEGConfig variable from being a TXMLDocument* raw pointer to being a _di_IXMLDocument smart pointer that manages the interface's reference count. You need to do the same for your IXMLNode* raw pointers, too. Use _di_IXMLNode instead. Also, because they are reference counted objects, make sure they go out of scope (or are explicitly Release() 'ed) before you call CoUninitialize(). Also, do not 'new' an Exception that you are going to 'throw'. Throw it by value rather than by pointer. This is the one and only place where Delphi-style classes (ie, classes derived from TObject) are allowed to be created without 'new' in C++Builder. Try this: if (FAILED(CoInitializeEx(0, COINIT_SPEED_OVER_MEMORY))) { return; } try { TDOMVendor *vendor = DOMVendors->Find(_D("MSXML")); if (vendor == NULL) { throw Exception(_D("vendor MSXML XML wasn't found'")); } _di_IXMLDocument pMEGConfig = new TXMLDocument(NULL); // or: _di_IXMLDocument pMEGConfig = NewXMLDocument(); pMEGConfig->DOMVendor = vendor; pMEGConfig->LoadFromFile(_D("An XML FILE")); pMEGConfig->Active = true; _di_IXMLNode ROOT = pMEGConfig->DocumentElement; ... } __finally { CoUninitialize(); } Alternatively: if (FAILED(CoInitializeEx(0, COINIT_SPEED_OVER_MEMORY))) { return; } try { DefaultDOMVendor = _D("MSXML"); _di_IXMLDocument pMEGConfig = LoadXMLDocument(_D("An XML FILE")); _di_IXMLNode ROOT = pMEGConfig->DocumentElement; ... } __finally { CoUninitialize(); }
  3. Remy Lebeau

    custom TTreeView

    You are storing custom allocated data in the TTreeNode.Data property. To free that memory, you can override the TreeView's virtual Delete() method, which is called for every TTreeNode object that gets destroyed at runtime, eg: type TmyDBTreeView = class(TTreeView) protected procedure Delete(Node: TTreeNode); override; end; procedure TmyDBTreeView.Delete(Node: TTreeNode); begin inherited Delete(Node); // fires the OnDeletion event handler Dispose(PNodeRec(Node.Data)); Node.Data := nil; end; However, a better way to handle this is to not use the TTreeNode.Data property at all. Leave that untouched so users of your component can use it for their own application data. Instead, you should create a custom descendant of TTreeNode to hold your component's extra data, and then you can override the TreeView's virtual CreateNode() method to return new instances of your custom Node class, eg: type TmyDBTreeNode = class(TTreeNode) public IdNode: integer; IdParent : integer; end; TmyDBTreeView = class(TTreeView) protected function CreateNode: TTreeNode; override; end; function TmyDBTreeView.CreateNode: TTreeNode; begin Result := TmyDBTreeNode.Create(Items); end; Then, any place that you were accessing PNodeRec(Node.Data)^ before, you can instead access TmyDBTreeNode(Node), for example: // if DataSource.DataSet.FieldByName(IDParentNode).AsInteger = PNodeRec(Node.Data)^.IdNode then if DataSource.DataSet.FieldByName(IDParentNode).AsInteger = TmyDBTreeNode(Node).IdNode then function TmyDBTreeView.GetNodeIdParent(Node: TTreeNode): integer; begin //Result := PNodeRec(Node)^.IdParent; Result := TmyDBTreeNode(Node).IdParent; end; function TmyDBTreeView.GetNodeId(Node: TTreeNode): integer; begin //Result := PNodeRec(Node)^.IdNode; Result := TmyDBTreeNode(Node).IdNode; end; And when adding new nodes to the TreeView, you don't need to use Add...Object() methods anymore, you can just use the normal Add...() methods instead, eg: //New(NRec); //NRec^.IdNode := DataSource.DataSet.FieldByName(IDNode).AsInteger; //NRec^.IdParent := DataSource.DataSet.FieldByName(IDParentNode).AsInteger; //Node := Items.AddObject(nil, DataSource.DataSet.FieldByName(DataField).AsString, NRec); Node := Items.Add(nil, DataSource.DataSet.FieldByName(DataField).AsString); TmyDBTreeNode(Node).IdNode := DataSource.DataSet.FieldByName(IDNode).AsInteger; TmyDBTreeNode(Node).IdParent := DataSource.DataSet.FieldByName(IDParentNode).AsInteger; // New(DNode); // DNode^.IdNode := DataSource.DataSet.FieldByName(FIDNode).AsInteger; // DNode^.IdParent := DataSource.DataSet.FieldByName(FIDParentNode).AsInteger; // NewNode := Items.AddChildObject(Node, Field.AsString, DNode); NewNode := Items.AddChild(Node, Field.AsString); TmyDBTreeNode(NewNode).IdNode := DataSource.DataSet.FieldByName(FIDNode).AsInteger; TmyDBTreeNode(NewNode).IdParent := DataSource.DataSet.FieldByName(FIDParentNode).AsInteger; --- That being said, I notice a number of other issues with your code, that are unrelated to node management. 1. Why do you have a Sleep() loop inside of your TmyDBTreeView destructor? Not only is a loop redundant when you could simply calculate the wanted duration in a single call, but calling Sleep() during destruction really doesn't belong there to begin with. 2. Any use of Items.(Begin|End)Update() should be protected with a try..finally block. 3. This code is wrong: procedure TmyDBTreeView.CMGetDataLink(var Message: TMessage); begin Message.Result := Integer(FDataLink); end; If you ever try to use your component in 64bit, this will fail as it will truncate the returned pointer. The Message.Result is a NativeInt, not an Integer, so cast accordingly. 4. Inside of TmyDBTreeView.SetDataSource(), since you are calling FreeNotification() on a new DataSource, you should call RemoveFreeNotification() on any DataSource that was previously assigned. Although, I think this is completely redundant since you are not actually storing a reference to the DataSource, you are just assigning it to your DataLink, so you could just remove use of FreeNotification() altogether and let the DataLink handle that for you. Also, SetDataSource() is assigning the new DataSource to your DataLink only if csLoading is enabled, which means it is being assigned only during DFM streaming. But if a user of your component decides to change the DataSource at runtime after the DFM is loaded, you are not updating your DataLink. 5. in TmyDBTreeView.DeleteNodeFromTreeOnly(), you are looping incorrectly. Since you are looping forwards, if a node is deleted then your loop counter will get out of sync and end up skipping the next node. To account for that, you need to either: a. loop backwards instead of forwards, eg: procedure TmyDBTreeView.DeleteNodeFromTreeOnly(id_node: integer); var i: integer; begin for i := Items.Count - 1 downto 0 do begin //if PNodeRec(Items[i])^.IdNode = id_node then Items[i].Delete; if TmyDBTreeNode(Items[i]).IdNode = id_node then Items[i].Delete; end; end; b. change the loop so your 'i' variable is incremented only when a node is NOT deleted, eg: procedure TmyDBTreeView.DeleteNodeFromTreeOnly(id_node: integer); var i, cnt: integer; begin i := 0; cnt := Items.Count; while i < cnt do begin //if PNodeRec(Items[i])^.IdNode = id_node then Items[i].Delete then if TmyDBTreeNode(Items[i]).IdNode = id_node then Items[i].Delete then Dec(cnt) else Inc(i); end; end;
  4. Remy Lebeau

    GetCryptLibHandle Issue on ios

    I'm not familiar with those libraries. In fact, I've never even heard of them before. Indy uses static linking on iOS devices. It uses dynamic loading on every other platform, including iOS Simulator. https://docwiki.embarcadero.com/RADStudio/en/OpenSSL At the time when iOS support was first added to Indy, Apple supported only static libraries on iOS. I think that has changed in recent years, but Indy has not been updated to support that yet. Contact the author of those other libraries and find out why they are trying to access an Indy function that doesn't exist on iOS devices.
  5. Remy Lebeau

    Passive, non interactive custom form

    Override the Form's CreateParams() method to enable the WS_EX_NOACTIVATE extended style: procedure CreateParams(var Params: TCreateParams); override; ... procedure TMyForm.CreateParams(var Params: TCreateParams); begin inherited; Params.WindowClass.ExStyle := Params.WindowClass.ExStyle or WS_EX_NOACTIVATE; end;
  6. Remy Lebeau

    Placing Child Behind Parent

    Yes, but that is not a big deal at all.
  7. Remy Lebeau

    Placing Child Behind Parent

    OK, so then simply make the TRectangle be the Owner of the TImage, but make the TRectangle and TImage be siblings of the same parent, instead of making the TRectangle be the parent of the TImage. This way, the TImage can go behind the TRectangle, and you can move the TImage whenever the TRectangle is moved and vice versa, unless the Ctrl key is down. This is exactly how VCL controls like TLabeledEdit are implemented, for example.
  8. Remy Lebeau

    Placing Child Behind Parent

    Of course not. VCL does not support that either. Why would you ever want a child to go behind its parent?
  9. Remy Lebeau

    Cecking Application Execution

    That code can't possibly work as you propose. For one thing, you can't determine parent/child relationships using EnumProcesses(). It only gives you a flat array of all the running process IDs at that moment, there is no guarantee as to their order in the array. Second, you are simply looking for the caller's passed-in PID in the array, and when found then you are opening a HANDLE to that process and querying its PID - the same PID that you already have! GetProcessId() does not give you a parent PID. The only APIs I am aware of that can provide you with a parent PID are: CreateToolhelp32Snapshot() + Process32(First|Next)() NtQueryInformationProcess() So, for example, using Toolhelp32: function GetParentProcessID(const AProcessID: DWORD): DWORD; var hSnapshot: THandle; pe: PROCESSENTRY32; begin Result := 0; hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if hSnapshot <> INVALID_HANDLE_VALUE then try pe.dwSize := SizeOf(dwSize); if Process32First(hSnapshot, pe) then repeat if pe.th32ProcessID = AProcessID then begin Result := pe.th32ParentProcessID; Exit; end; until not Process32Next(hSnapshot, pe); finally CloseHandle(hSnapshot); end; end; Or, using NTDLL: function GetParentProcessID(const AProcessID: DWORD): DWORD; var hProcess: THandle; pbi: PROCESS_BASIC_INFORMATION; begin Result := 0; hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, AProcessID); if hProcess <> 0 then try if NtQueryInformationProcess(hProcess, ProcessBasicInformation, @pbi, SizeOf(pbi), nil) = STATUS_SUCCESS then Result := DWORD(pbi.InheritedFromUniqueProcessId); finally CloseHandle(hProcess); end; end;
  10. Remy Lebeau

    Cecking Application Execution

    It is also possible to check if your process is being executed by a .lnk shortcut, by using the GetStartupInfo() API and checking the STARTUPINFO.dwFlags field for the STARTF_TITLEISLINKNAME flag.
  11. Remy Lebeau

    coff2omf does not create any output or error messages

    Why? For an import lib, you should instead simply create a new import lib file for C++Builder using the IMPLIB (32bit) or MKEXP (64bit) tool on the DLL itself. There is no point in converting import libs, only static libs.
  12. Remy Lebeau

    Hosting a console in a Delphi Application

    Yes, they do, but those child processes are specifically designed to interoperate and sync with their host process. That is not the case when you simply host someone else's UI inside of your own. That is when bad things can happen, because the child process doesn't know it's being hosted and so the parent and child don't sync their states together.
  13. Remy Lebeau

    Hosting a console in a Delphi Application

    There is no GetProcessWindow() function in the Win32 API, since windows are not tied to processes, only to threads. So I'm assuming that function is implemented in your own code, yes? Probably a combination of EnumWindows() and GetWindowThreadProcessId(), though using EnumThreadWindows() with the pi.dwThreadID instead might make more sense. That can be very dangerous if you are not careful. Is it legal to have a cross-process parent/child or owner/owned window relationship?
  14. Remy Lebeau

    converting float to text

    The '%f' specifier in ...printf() style functions expects 'double' (or 'long double' if you use '%Lf'), not 'float'. There is no specifier that accepts 'float'. So, you will have to cast the values when passing them in, eg: snprintf(buffer, sizeof(buffer), "%f", (double) *zMap); // or: double(*zMap), or static_cast<double>(*zMap) Alternatively, you can format the 'float' to a C++ 'std::string' first, and then copy it into your buffer, eg: std::ostringstream oss; oss << *zMap; strncpy(buffer, oss.str().c_str(), sizeof(buffer)-1); Or: strncpy(buffer, std::format("{}", *zMap).c_str(), sizeof(buffer)-1); Of course, being a Delphi guy, you could just use the Delphi RTL in C++Builder to convert the 'float' to a 'System::String' first, and then copy it into your buffer, eg: strncpy(buffer, AnsiString(FloatToStr(*zMap)).c_str(), sizeof(buffer)-1); // or simpler: strncpy(buffer, AnsiString(*zMap).c_str(), sizeof(buffer)-1); Or, simply get rid of the buffer altogether and use the 'std::string'/'System::(Ansi)String' as-is instead. That being said, your two examples are logically equivalent, so if the above approaches don't fix the issue, then make sure the pointer being returned by SomeFunctionThatReturnsABuffer() is actually valid to begin with (ie, that the memory buffer is not being freed before you copy the data, etc).
  15. Remy Lebeau

    ReleaseExceptionObject not working?

    I question the design of the code shown. I would have opted to implement it more like this instead: procedure AnalyzeException(const E: Exception); begin // ...Do something with the object ... end; procedure TestCase (ReRaiseException {or: SwallowException}: Boolean); var OneThousand, Zero: integer; d: double; begin Zero := 0; OneThousand := 1000; try d := OneThousand / Zero; except on E: Exception do begin AnalyzeException(E); if ReRaiseException {or: not SwallowException} then raise; end; end; end;
  16. Remy Lebeau

    Clipboard how to detect it contain files on Firemonkey ?

    Unfortunately, you will not be able to do that with FMX's native interfaces, at least on Windows (I didn't look at other platforms). You will have to resort to using the Win32 API directly. On Windows, FMX's default IFMXClipboardService implementation natively supports only the CF_UNICODETEXT and CF_DIB standard clipboard formats. For other clipboard formats, FMX does offer IFMXExtendedClipboardService. However, it only supports clipboard formats that are registered at runtime via its RegisterCustomFormat() method, which on Windows is based on the Win32 RegisterClipboardFormat() API. But files are stored on the Windows clipboard using pre-defined Shell clipboard formats that are not registered at runtime (ie, CF_HDROP, CF_FILENAME, CFSTR_FILEDESCRIPTOR+CFSTR_FILECONTENTS, CFSTR_SHELLIDLIST, etc), so they cannot be accessed with IFMXExtendedClipboardService at this time. I have just now opened a QualityPortal ticket to request that feature be added in a future Delphi release: RSP-41923: Allow IFMXExtendedClipboardService to access custom formats by ID, not just by name For Windows, definitely yes. For other platforms, it depends on how their system clipboards store files, and how FMX implements support for them, but I suspect the answer will be yes for them as well.
  17. @bravesofts This was already covered on your StackOverflow question yesterday: delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices? Guess you didn't like what you were told there? So you came here instead, just to be told the same things. Funny how the same knowledge can span across multiple forums, huh? 😉
  18. Can you please show the code in SolidBridge.h, as well as the Delphi code it is based on? What do you mean, exactly? VCL's TApplication::MessageBox() method simply calls the Win32 API MessageBox() function, using either TApplication::ActiveFormHandle or TApplication::Handle as the owner window for the dialog. So, it does not use any VCL font resources.
  19. Remy Lebeau

    _argc

    Putting the program name in argv[0] is only a convention, not a guarantee. It depends on how the caller passes parameters when spawning the process. And it is possible to spawn a process without the program name as the first parameter. You can instead use ParamStr(0) (or Application->ExeName in VCL) to get the program name.
  20. Remy Lebeau

    How to access RTTI property(class type) and play on

    No. AProp2 is just a TRttiProperty, you can't cast it to anything that is related to the actual object. You can't specify Generic parameters at runtime, only at compile-time. So you will have to change GetById() into a normal function that takes a TClass input parameter, eg: function TEntityManager.GetById(ClassType: TClass; AID: Int64, ALock: Boolean = False): TObject; ... AProp.SetValue(LObj, Self.GetById(LObj.ClassType, LRelationID, ALock));
  21. I think only {$WARN} has that option, but most other directives do not.
  22. Remy Lebeau

    How to access RTTI property(class type) and play on

    You are not actually reading the TPerson.Address property value to access the TAddress object. AProp.PropertyType.AsInstance is not the way to do that, use AProp.GetValue() instead and cast the result to an object pointer, eg: var ... LObj: TObject; ... for AProp in ARelations do begin LObj := AProp.GetValue(SomeModel).AsObject; LClass := LObj.ClassType; for AProp2 in AProp.PropertyType.GetProperties do begin if (AProp2.Visibility in [mvPublished, mvPublic]) then begin for LAttr in AProp2.GetAttributes do begin if (LAttr is ColumnAttribute) then begin if (AProp2.PropertyType.TypeKind in [tkString, tkUString, tkWString]) then AProp2.SetValue(LObj, 'Orange'); Break; end; end; end; end; end; ...
  23. Remy Lebeau

    How to Sort TStringList ?

    Yes, simply use TStringList.CustomSort() to sort the strings however you want, eg: function MySortFunc(List: TStringList; Index1, Index2: Integer): Integer; begin Result := StrToInt(Copy(List[Index2], 4, MaxInt)) - StrToInt(Copy(List[Index1], 4, MaxInt)); end; ... var SL: TStringList; SL := TStringList.Create; ... SL.Add('ABC10'); SL.Add('ABC1'); SL.Add('ABC2'); SL.Add('ABC21'); SL.CustomSort(@MySortFunc); ... SL.Free;
  24. Remy Lebeau

    SvCom - Services 64bit on Delphi 11.3

    I don't have SvCom's source code to look at, but offhand I would appear that SvSetservicestatus() is acting as some kind of proxy and is using ASM to preserve the original call stack when jumping into other functions, rather than pushing its own data onto the call stack using normal function calls.
  25. Remy Lebeau

    Line number at build/compile time??

    In C++, yes (via __LINE__), and even in FreePascal, yes (via {$INCLUDE %LINE%}), but not in Delphi, no.
×