Created
March 10, 2014 07:52
-
-
Save harvimt/9461046 to your computer and use it in GitHub Desktop.
lib7zip minimal c example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <windows.h> | |
#include <wchar.h> | |
#include <initguid.h> | |
#include "pstdint.h" | |
DEFINE_GUID(CLSID_CFormat7z, | |
0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); | |
DEFINE_GUID(IID_IInArchive, | |
0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00); | |
typedef struct { | |
HRESULT (*QueryInterface) (void*, GUID*, void**); | |
uint32_t (*AddRef)(void*); | |
uint32_t (*Release)(void*); | |
HRESULT (*Read)(void* self, uint8_t *data, uint32_t size, uint32_t *processedSize); | |
HRESULT (*Seek)(void* self, int64_t offset, uint32_t seekOrigin, uint64_t *newPosition); | |
} _IInStream_vtable; | |
typedef struct{ | |
_IInStream_vtable* vtable; | |
uint32_t num_refs; | |
FILE* file; | |
} IInStream; | |
typedef struct { | |
HRESULT (*QueryInterface) (void*, GUID*, void**); | |
uint32_t (*AddRef)(void*); | |
uint32_t (*Release)(void*); | |
HRESULT(*SetTotal)(void* self, const uint64_t *files, const uint64_t *bytes); | |
HRESULT(*SetCompleted)(void* self, const uint64_t *files, const uint64_t *bytes); | |
} _IArchiveOpenCallback_vtable; | |
typedef struct { | |
_IArchiveOpenCallback_vtable* vtable; | |
uint32_t num_refs; | |
} IArchiveOpenCallback; | |
typedef void IArchiveExtractCallback; /* FIXME */ | |
typedef struct { | |
HRESULT (*QueryInterface) (void*, GUID*, void**); | |
uint32_t (*AddRef)(void*); | |
uint32_t (*Release)(void*); | |
HRESULT (*Open)(void* self, IInStream *stream, const uint64_t *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback); | |
HRESULT (*Close)(void* self); | |
HRESULT (*GetNumberOfItems)(void* self, uint32_t *numItems); | |
HRESULT (*GetProperty)(void* self, uint32_t index, PROPID propID, PROPVARIANT *value); | |
HRESULT (*Extract)(void* self, const uint32_t* indices, uint32_t numItems, uint32_t testMode, IArchiveExtractCallback *extractCallback); | |
HRESULT (*GetArchiveProperty)(void* self, PROPID propID, PROPVARIANT *value); | |
HRESULT (*GetNumberOfProperties)(void* self, uint32_t *numProperties); | |
HRESULT (*GetPropertyInfo)(void* self, uint32_t index, wchar_t **name, PROPID *propID, VARTYPE *varType); | |
HRESULT (*GetNumberOfArchiveProperties)(void* self, uint32_t *numProperties); | |
HRESULT (*GetArchivePropertyInfo)(void* self, uint32_t index, wchar_t **name, PROPID *propID, VARTYPE *varType); | |
} _IInArchive_vtable; | |
typedef struct{ | |
_IInArchive_vtable* vtable; | |
} IInArchive; | |
typedef HRESULT (__cdecl* _GetNumberOfFormats)(uint32_t *); | |
typedef HRESULT (__cdecl* _GetNumberOfMethods)(uint32_t *); | |
typedef HRESULT (__cdecl* _GetMethodProperty)(uint32_t index, PROPID propID, PROPVARIANT * value); | |
typedef HRESULT (__cdecl* _GetHandlerProperty2)(uint32_t, PROPID propID, PROPVARIANT *); | |
typedef HRESULT (__cdecl* _CreateObject)(const GUID *, const GUID *, void **); | |
#define kpidPath 3 | |
#define kpidCRC 19 | |
/** IInStream impl **/ | |
HRESULT IInStream_QueryInterface(IInStream* self, GUID* iid, void** out_obj){ | |
puts("IInStream.QueryInterface"); | |
*out_obj = NULL; | |
return E_NOINTERFACE; | |
} | |
uint32_t IInStream_AddRef(IInStream* self){ | |
self->num_refs += 1; | |
printf("IInStream.AddRef: num_refs=%u\n", self->num_refs); | |
return self->num_refs; | |
} | |
uint32_t IInStream_Release(IInStream* self){ | |
self->num_refs -= 1; | |
printf("IInStream.Release: num_refs=%u\n", self->num_refs); | |
return self->num_refs; | |
} | |
HRESULT IInStream_Read(IInStream* self, uint8_t *data, uint32_t size, uint32_t *processedSize){ | |
puts("IInStream.Read"); | |
if(processedSize != NULL){ | |
*processedSize = fread(data, sizeof(uint8_t), size, self->file); | |
}else{ | |
fread(data, sizeof(uint8_t), size, self->file); | |
} | |
return S_OK; | |
} | |
HRESULT IInStream_Seek(IInStream* self, int64_t offset, uint32_t seekOrigin, uint64_t *newPosition){ | |
puts("IInStream.Seek"); | |
if(newPosition != NULL){ | |
*newPosition = _fseeki64(self->file, offset, seekOrigin); | |
}else{ | |
_fseeki64(self->file, offset, seekOrigin); | |
} | |
return S_OK; | |
} | |
/** IOpenArchiveCallback impl **/ | |
HRESULT IOpnArc_QueryInterface(IArchiveOpenCallback* self, GUID* iid, void** out_obj){ | |
puts("IOpenArchiveCallback.QueryInterface"); | |
*out_obj = NULL; | |
return E_NOINTERFACE; | |
} | |
uint32_t IOpnArc_AddRef(IArchiveOpenCallback* self){ | |
self->num_refs += 1; | |
printf("IArchiveOpenCallback.AddRef: num_refs=%u\n", self->num_refs); | |
return self->num_refs; | |
} | |
uint32_t IOpnArc_Release(IArchiveOpenCallback* self){ | |
self->num_refs -= 1; | |
printf("IArchiveOpenCallback.Release: num_refs=%u\n", self->num_refs); | |
return self->num_refs; | |
} | |
HRESULT IOpnArc_SetTotal(IArchiveOpenCallback* self, const uint64_t *files, const uint64_t *bytes){ | |
puts("IArchiveOpenCallback.SetTotal"); | |
return S_OK; | |
} | |
HRESULT IOpnArc_SetCompleted(IArchiveOpenCallback* self, const uint64_t *files, const uint64_t *bytes){ | |
puts("IArchiveOpenCallback.SetCompleted"); | |
return S_OK; | |
} | |
int testmain(){ | |
HMODULE lib; | |
_GetNumberOfFormats GetNumberOfFormats; | |
_GetHandlerProperty2 GetHandlerProperty2; | |
_CreateObject CreateObject; | |
IArchiveOpenCallback callback; | |
_IArchiveOpenCallback_vtable callback_vt; | |
IInStream in_stream; | |
_IInStream_vtable in_stream_vt; | |
uint64_t maxCheckStartPosition = 0; | |
IInArchive* archive; | |
uint32_t num_formats = 0; | |
puts("Starting"); | |
lib = LoadLibrary("C:\\Program Files\\7-Zip\\7z.dll"); | |
if(lib == NULL){ | |
lib = LoadLibrary("C:\\Program Files (x86)\\7-Zip\\7z.dll"); | |
if(lib == NULL){ | |
puts("lib is NULL"); | |
return 0; | |
} | |
} | |
GetNumberOfFormats = (_GetNumberOfFormats) GetProcAddress(lib, "GetNumberOfFormats"); | |
if(GetNumberOfFormats == NULL){ | |
puts("NULL FAIL"); | |
return 0; | |
} | |
GetHandlerProperty2 = (_GetHandlerProperty2) GetProcAddress(lib, "GetHandlerProperty2"); | |
if(GetHandlerProperty2 == NULL){ | |
puts("NULL FAIL"); | |
return 0; | |
} | |
CreateObject = (_CreateObject) GetProcAddress(lib, "CreateObject"); | |
if(CreateObject == NULL){ | |
puts("NULL FAIL"); | |
return 0; | |
} | |
/** Setup COM Structs **/ | |
in_stream_vt.QueryInterface = &IInStream_QueryInterface; | |
in_stream_vt.AddRef = &IInStream_AddRef; | |
in_stream_vt.Release = &IInStream_Release; | |
in_stream_vt.Read = &IInStream_Read; | |
in_stream_vt.Seek = &IInStream_Seek; | |
in_stream.vtable = &in_stream_vt; | |
in_stream.num_refs = 1; | |
in_stream.file = fopen("test.7z", "rb"); | |
callback.vtable = &callback_vt; | |
callback_vt.QueryInterface = &IOpnArc_QueryInterface; | |
callback_vt.AddRef = &IOpnArc_AddRef; | |
callback_vt.Release = &IOpnArc_Release; | |
callback_vt.SetTotal = &IOpnArc_SetTotal; | |
callback_vt.SetCompleted = &IOpnArc_SetCompleted; | |
callback.num_refs = 1; | |
/** Run **/ | |
if(GetNumberOfFormats(&num_formats) != 0){ | |
puts("FAIL!"); | |
return 0; | |
} | |
printf("num_formats=%u\n", num_formats); | |
if(CreateObject(&CLSID_CFormat7z, &IID_IInArchive, (void**)&archive) != S_OK){ | |
puts("CreateObject Fail"); | |
goto free; | |
} | |
if(archive == NULL){ | |
puts("archive is NULL after CreateObject"); | |
goto free; | |
} | |
if(archive->vtable->Open(archive, &in_stream, &maxCheckStartPosition, &callback) != S_OK){ | |
puts("Open Fail"); | |
goto free; | |
} | |
{ | |
uint32_t num_items = 0; | |
uint32_t i; | |
PROPVARIANT path; | |
PROPVARIANT crc; | |
if(archive->vtable->GetNumberOfItems(archive, &num_items) != S_OK){ | |
puts("archive.GetNumberOfItems FAIL"); | |
goto close; | |
} | |
for(i = 0; i < num_items; i += 1){ | |
PropVariantInit(&path); | |
PropVariantInit(&crc); | |
archive->vtable->GetProperty(archive, i, kpidPath, &path); | |
archive->vtable->GetProperty(archive, i, kpidCRC, &crc); | |
if(crc.vt != VT_UI4){ | |
puts("crc has wrong vt"); | |
goto clear; | |
} | |
if(path.vt != VT_BSTR){ | |
puts("path has wrong vt"); | |
goto clear; | |
} | |
printf("path=%ls; crc=%x\n", path.bstrVal, crc.ulVal); | |
clear: | |
PropVariantClear(&path); | |
PropVariantClear(&crc); | |
} | |
} | |
close: | |
if(archive->vtable->Close(archive) != S_OK){ | |
puts("Close Fail"); | |
} | |
free: | |
puts("SOMETHING HAPPENED"); | |
puts(FreeLibrary(lib) ? "Free Successful" : "Free Unsuccessful"); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from cffi import FFI | |
ffi = FFI() | |
ffi.cdef(""" | |
void testmain(); | |
""") | |
with open("cffi_test.c", 'r') as f: | |
C = ffi.verify( | |
f.read() | |
, libraries=["ole32"], include_dirs=["."]) | |
print('VERIFICATION COMPLETE'); | |
C.testmain() | |
print('SOMETHING DEFINITELY HAPPENED'); |
Hi @harvimt, I found this example incredible due that the almost nonexistent documentation about 7z.dll library.
I'm having an issue in :
if (archive->vtable->Open(archive, &in_stream, &maxCheckStartPosition, &callback) != S_OK) {}
The application crash with: 0xC0000005: Access violation executing location 0x00000000.
archive => 0x007028a8 (valid pointer with accessible vtable)
in_stream => 0x0023f770 (valid pointer)
maxCheckStartPosition => 0 (valid pointer to uint64_t)
callback => 0x0023f7bc (valid pointer)
Do you know why this could be happening? I really appreciate your help!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on your idea, I have written C interface to 7z.so [edit: compatible with both WIndows and Linux/OSX]. Thank you so much.
https://gist.github.com/cielavenir/099bb17e673c734c1c13790835f77206