Jump to content

Anders Melander

Members
  • Content Count

    2854
  • Joined

  • Last visited

  • Days Won

    156

Posts posted by Anders Melander


  1. 1 minute ago, karl Jonson said:

    It's ansichar type

    I need to check if MyByteArray = MyansiChar (eg. control character EOT)

    As I wrote you cannot compare a byte (ansichar) to 13 bytes (byte array) for equality. Since the size is different they will always be different, so what you're asking isn't making sense.

     

    Are you trying to determine if the byte array contains the ansichar?

    function Contains(const Bytes: TByteArray; c: AnsiChar): boolean;
    begin
      for var b in Bytes do
        if (b = Ord(c)) then
          Exit(True);
      Result := False;
    end;

     


  2. I think you must have a bug somewhere else that is causing this. I can't spot a problem in the code you've posted.

    The following works for me with D10.3.1:

    function Test1: OleVariant;
    begin
      Result := VarArrayCreate([0, 1], varOleStr);
      Result[0] := 'Hello';
      Result[1] := 'World';
    end;
    
    function Test2: OleVariant;
    var
      V: OleVariant;
    begin
      V := VarArrayCreate([0, 1], varOleStr);
      V[0] := 'A kitten dies...';
      V[1] := '...every time you use variant arrays';
      Result := V;
    end;
    
    procedure DoTest;
    var
      V: OleVariant;
    begin
      V := Test1;
      V := Test2;
    end;

     

    Try reproducing the problem in a new empty application.


  3. 18 minutes ago, clubreseau said:

    why this freeze the APP and take 1 minut to load 10K of items ?

    Generally speaking, the API of most Windows common controls goes through the windows message queue. So my guess is that for each item in the listbox there's a lot of messages going back and forth while the listbox is populated and that's an enormous overhead.

    If you break the application in the debugger while the list is loading you can see what it's doing.


  4. 48 minutes ago, Mike Torrettinni said:

    Thank you, but that was very confusing to read, the whole page.

    Okay. I'll try with a simpler example (apologies to @Kas Ob. if he/she/they already covered it, but it's friday and TLDR).

     

    Byte code is just the instruction set for a specialized virtual CPU so in this case it's a virtual CPU that only knows how to search stuff.

     

    A byte code compiler is a compiler that transforms "something" (in this case search parameters) into the virtual CPU assembler.

    The implementation of the virtual CPU is called an interpreter if it executes the byte code instruction from scratch each time you execute the "byte code program". If it instead compiles the byte code into actual processor opcodes the first time and then execute those the first and subsequent times, then it's called just-in-time compiler.

     

    One of the first pascal implementation was UCSD Pascal which ran on the UCSD p-System - a byte code virtual machine.

     

    P.S. You really should try to read about and understand these old concepts. While they might not seem relevant to you now, understanding and knowing about them can only improve your skills.

    wall_o__text.thumb.jpg.4e975a4a7c65d1b489e7070bd3f73801.jpg

    • Like 1
    • Thanks 1

  5. So you are doing it with Outlook which again prompts me to ask why you're not also handling the eml files the same way (after importing them into Outlook) instead of handling them in two different ways?

     

    Personally I would probably:

    1. Load the msg file into an IStorage with StgOpenStorage
    2. Get an IMessage from the IStorage with OpenIMsgOnIStg
    3. Extract the IMessage properties with HrGetOneProp or IMessage.OpenProperty

  6. 1 minute ago, Mark Williams said:

    I am processing the email files for upload to a server. I don't need to add them to Outlook to do this. If I can open and handle them via TIDMessage it will save a significant amount of time.

    Yes I understood that. I was talking about your statement : "drop the msg files into Outlook and handle them there somehow".


  7. 37 minutes ago, Mark Williams said:

    ... and Outlook for any emails TIDMessage can't handle by adding the latter to a temp folder in Outlook, processing and then removing the temp folder (subject to me working out exactly how I do that!).

    If I'm understanding what you're saying you are going drop the msg files into Outlook and handle them there somehow. If that's an option then why not also handle the eml files this way?


  8. 16 minutes ago, Mark Williams said:

    Off hand do you happen to know if most other email types are also structured storage files?

    I would guess that no other types use it. It's not a very friendly format.

     

    18 minutes ago, Mark Williams said:

    Do you (or anyone) happen to know know if the IMessage interface will work with other email types or just Outlook? 

    I can't speak authoritatively on the subject but if IMessage is a MAPI interface then in theory it should work with all MAPI providers. Unfortunately I don't think there's many applications left that support MAPI.

     

    23 minutes ago, Mark Williams said:

    I would really appreciate any feedback on whether TIDMessage can handle MSG files

    I doubt it but it should be easy to determine since you have the source...

    • Thanks 1

  9. Outlook msg files are COM Structured Storage files in the CFB3 (Compound File Binary) format.

    Here's file file format specification: http://msdn.microsoft.com/en-us/library/cc463912.aspx

     

    You can use the IStorage interface to load the file (via IStream) but you will need to locate and extract the desired properties manually. You can find tons of code on the net that shows how to do that and I think the above specs contains the names of the properties. I also think the last version of the Drag and Drop Component Suite I released even contained some code that did it.

     

    AFAIR there's also an OpenIMsgOnIStg API function that can do some of the work for you but I think it might require that Outlook is installed.

    • Thanks 1

  10. Just now, A.M. Hoornweg said:

    I'd like to take a closer look at it at the very least !

    Okay, here you go. Source and simple demo attached.

     

    Usage:

    Producer

    var FRingBuffer := TSharedMemoryRingBuffer.Create('FooBar', 1024*1024); // 1Mb
    ...
    
    // String
    FRingBuffer.Enqueue('Hello world');
    
    // Raw bytes
    var Buffer: TBytes;
    ...
    FRingBuffer.Enqueue(Buffer);

    Consumer

    var FRingBuffer := TSharedMemoryRingBuffer.Create('FooBar', 1024*1024); // 1Mb
    ...
    
    // Strings
    while (True) do
    begin
      // Just remove the WaitFor to use polling instead
      if (FRingBuffer.WaitFor(100) = wrSignaled) then
      begin
        var s. string;
        if (FRingBuffer.Dequeue(s)) then
          ...do something with string...
      end;
      ...
    end;
    
    // Raw bytes
    while (True) do
    begin
      // Just remove the WaitFor to use polling instead
      if (FRingBuffer.WaitFor(100) = wrSignaled) then
      begin
        var Buffer: TBytes;
        if (FRingBuffer.Dequeue(Buffer)) then
          ...do something with buffer...
      end;
      ...
    end;

     

    amSharedMemory.pas

    SharedMemory.zip

    • Like 2

  11. @A.M. Hoornweg Thanks for the detailed explanation. I understand your challenge much better now.

     

    I think it's essential that you realize that the overhead of the lock itself is not going to be a factor at all and instead focus on minimizing the time the lock is held - i.e. the time to transfer data to and from the shared memory buffer. My recommendation would be to start with a simple solution and if that turns out not to be fast enough then you can try to come up with something better.

    I don't know anything about the actual amount of data you're processing but I think I would strive to process it in many small chunks instead of few large chunks. On the producer side I would write data packets to a (fast) lock free queue and have a separate thread read from that queue and write them to the (slower) shared memory queue. If it's essential that the producer isn't blocked then you will have to accept that data can be dropped if the consumer isn't able to keep up, but I guess you already know that.

    Again, if you want it I have a ready to use implementation of a shared memory circular buffer that has been used in production for many, many years.


  12. 1 hour ago, A.M. Hoornweg said:

    The producer writes into the ring buffer @ 10Hz, the consumer polls the ring buffer every few seconds and pulls whatever was put in there.

    Are you kidding me?

    What you are asking for is apparently a wheelbarrow while the rest of us are suggesting different ways to build a drag racer :classic_smile:

     

    I don't get why you don't just use a TMutex to protect the ring buffer structure and a TSemaphore to signal availability. I mean it's like around 10 lines of extra code compared to the 2-300 lines of code you will need to implement the ring buffer in shared memory.

     

    1 hour ago, A.M. Hoornweg said:

    A synchronization object is only needed for atomicity of the pointers and counters.

    You're aware that you can't store pointers in shared memory, right?


  13. Why not just use the traditional synchronizations mechanism provided by the OS and keep things simple? It seems pointless focusing on micro optimizing the concurrency control of a buffer backed by virtual memory and accessed synchronously. The sync mechanism is not going to be the bottleneck.

     

    I have the code for a shared memory ring buffer somewhere if the OP is interested. I used it a few decades ago to pipe CodeSite log messages between a producer and a consumer service. The consumer wrote the log to disk.

    • Like 1

  14. On 10/28/2020 at 4:45 PM, Phil Brinkle said:

    Your code works fine and it returns 36 functions for me

    Those are just the WMI methods and they are all documented.

    https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject

     

    If you want to talk to a COM server why are you then going through WMI? Are you sure it isn't a WMI Provider you are talking about?

     

    52 minutes ago, Phil Brinkle said:

    I am working with an undocumented COM server.

    If you install the Windows SDK (just the tools parts) there's a utility in it called OleView that you can use to examine type libraries and COM servers.

     

    The type library of your server is probably embedded in the EXE file.

     

    Edit: If it's a WMI provider then it's probably a DLL and it's probably early bound and without a type library. It depends on what kind of provider it is.

    • Like 1
×