Using 7zip Delphi wrapper from C++ Builder - delphi

I'm trying to utilize "7za.dll" together with this Delphi wrapper - http://www.progdigy.com/?page_id=13
Having difficulties translating this code to C++ and understanding the wrapper itself:
procedure TMainForm.ExtractAllClick(Sender: TObject);
var Arch: I7zOutArchive;
begin
Arch := CreateOutArchive(CLSID_CFormat7z);
// add a file
Arch.AddFile('c:\test.bin', 'folder\test.bin');
// add files using willcards and recursive search
Arch.AddFiles('c:\test', 'folder', '*.pas;*.dfm', true);
// add a stream
Arch.AddStream(aStream, soReference, faArchive, CurrentFileTime, CurrentFileTime, 'folder\test.bin', false, false);
// compression level
SetCompressionLevel(Arch, 5);
// compression method if <> LZMA
SevenZipSetCompressionMethod(Arch, m7BZip2);
// add a progress bar ...
Arch.SetProgressCallback(...);
// set a password if necessary
Arch.SetPassword('password');
// Save to file
Arch.SaveToFile('c:\test.zip');
// or a stream
Arch.SaveToStream(aStream);
end;
I've made additional wrapper of wrapper Delphi unit which when included in C++ code wraps above and it works. Now I'd like to use it a step further - call the above in C++ code directly.
How do I initialize, construct and release this I7zOutArchive interface properly in C++?
Is there a need to destroy (free memory) in above code or is it automatic when it goes out of scope (I usually use boost::scoped_ptr to do the job, is something like that required here)?

You do need to destroy the thing returned by CreateOutArchive, but scoped_ptr would be inappropriate. Instead, use the built-in System::DelphiInterface class:
System::DelphiInterface<I7zOutArchive> Arch = CreateOutArchive(CLSID_CFormat7z);
Then, call methods on that object the same as you would any other COM interface. (Replace Delphi's . operator with ->, and you're most of the way there.) The object will get destroyed when the reference count reaches zero, which generally occurs when Arch goes out of scope.

Related

Include multi-selection option in file-open-dialog

To allow multiselection in a file-open-dialog and to avoid this long expression:
OpenDialogSourceFiles.Options := OpenDialogSourceFiles.Options + [Vcl.Dialogs.fdoAllowMultiSelect]; // works
I tried to use the shorter Include function:
System.Include(OpenDialogSourceFiles.Options, Vcl.Dialogs.fdoAllowMultiSelect); // error
However, the compiler marks this as erroneous.
This is by design. The Include procedure requires a variable as its first argument (it is a var parameter, essentially, even though the procedure is implemented by compiler magic), but TFileOpenDialog.Options is a property.
Hence you must use the verbose alternative. There's nothing you can do about it.
The same thing applies to Inc and TComponent.Tag, for instance.
(But you can write fdoAllowMultiSelect instead of Vcl.Dialogs.fdoAllowMultiSelect, Include instead of System.Include, etc. to make it a bit less verbose.)

How to find if an IHTMLDocument2 is equal to IDispatch document in Delphi?

I have a TEmbeddedWB (https://sourceforge.net/projects/embeddedwb/) with an iFrame in it. I have to find out that a specific HTML Tag is inside that iFrame or not. My iFrame object is a IHTMLFrameBase2, while the Tag is a IHTMLElement. I know that the iFrame.contentWindow.document (which is a IHTMLDocument2) is the same as Tag.document. But the Tag.document is an IDispatch object, therefore the following gives a false:
if iFrame.contentWindow.document = Tag.document then ShowMessage('In iFrame')
else ShowMessage('Not in iFrame');
I know that the two object is the same, because the Watch List can show their memory address:
But I can't get their addresses from code. What I've tried:
Addr(iFrame.contentWindow.document) // Gives variable required error
#iFrame.contentWindow.document // Gives variable required error
Pointer(iFrame.contentWindow.document) //Compiles, but gives wrong address
Format('%p',[iFrame.contentWindow.document]) //Compiles, but gives EConvertError
Note: If I run line-by-line the addresses that the Watch List is showing change after EVERY line of code, no matter the code affects the WebBrowser or not.
From the rules of COM:
It is required that any call to QueryInterface on any interface for a given object instance for the specific interface IUnknown must always return the same physical pointer value. This enables calling QueryInterface(IID_IUnknown, ...) on any two interfaces and comparing the results to determine whether they point to the same instance of an object (the same COM object identity).
So, ask them both for their IUnknown interface, and compare.
var
disp: IDispatch;
doc: IHTMLDocument2;
....
if (disp as IUnknown) = (doc as IUnknown) then
....

with or without & for calling Synchronize() in C++ builder

My Environment:
OS - Windows7 Pro(32bit)
IDE - RadStudio XE2 Update4
I am wondering about Synchronize() function.
The Synchronize() function is used in the thread program. About using the Synchronize() in C+ builder, the example is as follows ( as can be seen in here)
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(&UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall TMyThreadClass::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
What I am confused is that , in some older version of C++ builder (e.g. bcb6),
the Synchronize() was used
// Synchronize(UpdateCaption);
without "&" before the function name;
Also in the delphi code as in here,
there is no "&" before the function name;
// Synchronize(UpdateCaption);
So, which is the correct way to use Synchronize() in C++ builder
// Synchronize(UpdateCaption);
or
// Synchronize(&UpdateCaption);
I tried both in the actual code, but seems identical in the working manner.
Do both UpdateCaption and &UpdateCaption return address of functions?
So, which is the correct way to use Synchronize() in C++ builder
// Synchronize(UpdateCaption);
or
// Synchronize(&UpdateCaption);
They both work, but & is preferred.
Do both UpdateCaption and &UpdateCaption return address of functions?
Yes. If you refer to a function/method without specifying parenthesis for the parameter list, the address of the function/method is assumed. The & just makes it more explicit.

SetUnhandledExceptionFilter : Continue execution 1 opcode further

I'm working on an Xbox1 emulator in Delphi, and because I run the games on the local CPU I have to create a failsafe for ring0 instructions that can occur inside the game-code.
To be able to trap these instructions, I've learned that SetUnhandledExceptionFilter can register a function that's going to be called on non-Delphi exceptions (provided I set JITEnable to a value above 0). The signature of the registered callback function reads :
function ExceptionFilter(E: LPEXCEPTION_POINTERS): Integer; stdcall;
Inside that function, I can test for illegal instructions like this :
// STATUS_PRIVILEGED_INSTRUCTION = $C0000096
if E.ExceptionRecord.ExceptionCode = STATUS_PRIVILEGED_INSTRUCTION then
One of the offending instructions is WVINDB ($0F,$09) which I can detect like this :
// See if the instruction pointer is a WBINVD opcode :
if (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[0] = #$0F)
and (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[1] = #$09) then
This all works (provided I run this outside the debugger) but I can't get the code to execute beyond the failing instruction - I tried it like this:
begin
// Skip the WBINVD instruction, and continue execution :
Inc(DWORD(E.ExceptionRecord.ExceptionAddress), 2);
Result := EXCEPTION_CONTINUE_EXECUTION;
Exit;
end;
Alas, that doesn't work. Actually, I would have used the real instruction pointer (E.ContextRecord.Eip), but somehow the entire ContextRecord doesn't seem populated.
What can I do so this does work as intended?
PS: When running with the debugger, I would expect this code to end up in my ExceptionFilter routine, but it doesn't - it only works without the debugger; Why's that?
DebugHook := 0; // Act as if there's no debugger
// Trigger a privileged instruction exception via this ring0 instruction :
asm
WBINVD
end;
// Prove that my exception-filter worked :
ShowMessage('WBINVD succesfully ignored!');
SetUnhandledExceptionFilter seems to be some kind of Delphi wrapper, maybe you have more luck if you do it directly?
You can register your own Exception handler with AddVectoredExceptionHandler, this will call a callback function that gives you an EXCEPTION_POINTERS structure. The Context member of that structure returns ao EIP which you can modify.
If you return EXCEPTION_CONTINUE_EXECUTION in the Callback execution continues at the given EIP.

Increasing a pointer not compiling the way I had planned

I tried to make my code as simple as possible,but I failed at it.
This is my code:
class function TWS.WinsockSend(s:integer;buffer:pointer;size:word):boolean;
begin
dwError := Send(s,buffer,size,0);
// Debug
if(dwError = SOCKET_ERROR) then
begin
dwError := WSAGetLastError;
CloseSocket(s);
WSACleanup;
case (dwerror) of
//Case statement
else
LogToFile('Unhandled error: ' + IntToStr(dwError) + ' generated by WSASend');
end;
Exit(false);
end;
// if the size of the bytes sent isn't the expected one.
while(dwError <> size) do
dwError:= dwError + Send(s,Ptr(cardinal(buffer) + dwError),size-dwError,0);
Exit(true);
end;
The error is placed at
dwError:= dwError + Send(s,Ptr(cardinal(buffer) + dwError),size-dwError,0);
Error is "Constant object cannot be passed as var parameter"
I understand I need a variable,but isn't there a way I can do it without adding one more line?
When the compiler complains about the way you're passing a parameter, the first thing you need to know is what the parameter expects. Therefore, you should go look at the declaration of Send. If looking at the declaration doesn't immediately give you an idea of what to fix, then you need to include that declaration with the code you post in your question.
I suspect that this actually has nothing to do with incrementing a pointer. Instead, the compiler is complaining about the third parameter, where you are trying to pass the expression size-dwError. I guess the parameter is declared like this:
var buffersize: Word;
The function plans on providing a new value for that parameter — that's what var means — so the thing you pass to that parameter needs to be something that can receive a value. You can't assign a new value to the result of subtracting two variables.
Take a closer look at where the compiler complained about that line. Didn't it place the cursor somewhere near the third parameter? That's a clue that the problem is there.
Decrement size, and then pass it to the function.
Dec(size, dwError);
Inc(dwError, Send(s, Ptr(cardinal(buffer) + dwError), size, 0));
Why do you care about adding another line? Have you reached your quota for the day? Lines are cheap; don't be afraid to use two to express yourself when one won't do. Likewise for variables. When your code doesn't work, saving a byte or two doesn't matter at all.
At the very least, you should have added more lines in order to track down the source of the problem. When you have one line of code that's performing several independent calculations (such as getting a new pointer value, getting a new size, and calling a function), break the line into several separate pieces. That way, if there's a problem with one of them and the compiler complains, you'll know exactly which one to blame.
Correct, this will not work as written. When your dealing with var parameters, you have to build the parameter BEFORE passing it to the procedure/function. When a Var parameter is passed, the procedure is allowed to modify it. If you attempted to copy two variables together on the call, where would this result go?
The other issue is that dwError is not delcared. A class method does NOT have access to the data elements of the object the class defines. If you drop the class, then you will have access to the data elements, but will require that the class first be created.
You should only be using class methods in places where the input and output are completely contained within the method.
How are you allocating your buffer? Internally is it an array?
Sounds like Send has a format parameter (like send (const something;size:integer)
Workaround is using pchar (entirepointerexpression)[0]

Resources