Difference between !sos.rcw and !sos.dumprcw output - clr

Recently I needed to debug a memory dump of a CLR process where the finalization queue was being blocked by a COM object. While I have largely identified the issue, I am not sure about the difference between some of the output and seek some clarification.
I used SOSEX to dump the RCWs. The output is as follows:
0:019> !sosex.rcw
SyncBlock OwnerObject RCW RefCount IUnknown VTable
------------------------------------------------------------------------------------------------------------
000000811807b238 0000008118251e18 00000081176b02e0 0 0000008116a6bc68 0061005c00730077
000000811807b5f8 00000081182b7380 0000008118104590 0 0000008116a6bc68 004d005c00730077
0000008562fed748 000000811831f498 0000008562fe7510 129 0000008116a6bc68 00000085632a2ee0
000000856300e168 00000084182ae2f0 0000008563082d00 0 0000008116a6bc68 000000856306a660
--------------
4 RCWs
Dumping the vtable does not help identify the COM object.
0:019> dps 00000085632a2ee0
00000085`632a2ee0 00007ffc`31832938 clr!DomainAssembly::`vftable'
00000085`632a2ee8 00000081`18099170
00000085`632a2ef0 00000085`631db8d0
00000085`632a2ef8 00000000`00000000
00000085`632a2f00 00007ffb`d24e4d20
00000085`632a2f08 0063006e`0000000c
00000085`632a2f10 00000085`1833ade9
00000085`632a2f18 00000000`00000000
00000085`632a2f20 00000001`00000007
00000085`632a2f28 00000000`00000000
00000085`632a2f30 00000000`00000000
00000085`632a2f38 00000000`00000000
00000085`632a2f40 00530041`002f0073
00000085`632a2f48 00000085`1833ade1
00000085`632a2f50 00000085`62fe7600
00000085`632a2f58 00000085`631dbd50
0:019> dps 00007ffc`31832938
00007ffc`31832938 00007ffc`31220ac0 clr!DomainAssembly::`vector deleting destructor'
00007ffc`31832940 00007ffc`311405d0 clr!CAssemblyIdentityManager::AddRef
00007ffc`31832948 00007ffc`3119e080 clr!DomainAssembly::Begin
00007ffc`31832950 00007ffc`3119fbe0 clr!DomainAssembly::Allocate
00007ffc`31832958 00007ffc`3119f0f0 clr!DomainAssembly::DeliverSyncEvents
00007ffc`31832960 00007ffc`3119e4d0 clr!DomainAssembly::DeliverAsyncEvents
00007ffc`31832968 00007ffc`311a01c0 clr!DomainAssembly::FindNativeImage
00007ffc`31832970 00007ffc`3160d630 clr!CorHostProtectionManager::QueryInterface
00007ffc`31832978 00007ffc`311405d0 clr!CAssemblyIdentityManager::AddRef
00007ffc`31832980 00007ffc`311405d0 clr!CAssemblyIdentityManager::AddRef
00007ffc`31832988 00007ffc`3160d660 clr!CorHostProtectionManager::SetProtectedCategories
00007ffc`31832990 00007ffc`31406100 clr!CorHostProtectionManager::SetEagerSerializeGrantSets
00007ffc`31832998 00007ffc`31500a30 clr!CCLRErrorReportingManager::QueryInterface
00007ffc`318329a0 00007ffc`311405d0 clr!CAssemblyIdentityManager::AddRef
00007ffc`318329a8 00007ffc`311405d0 clr!CAssemblyIdentityManager::AddRef
00007ffc`318329b0 00007ffc`314fcc50 clr!CCLRErrorReportingManager::GetBucketParametersForCurrentException
However, if I use !sos.dumprcw, a different vtable (and IUnknown) address is displayed:
0:019> !sos.dumprcw 0000008562fe7510
Managed object: 000000811831f498
Creating thread: 0000008562ff0050
IUnknown pointer: 000000811693a8d0
COM Context: 0000008116a6bc68
Managed ref count: 1
IUnknown V-table pointer : 00007ffc33609078 (captured at RCW creation time)
Flags:
COM interface pointers:
IP Context MT Type
000000811693a8d0 0000008116a6bc68 00007ffbd19db8c8 Microsoft.Web.Administration.Interop.IAppHostAdminManager
Dumping this "IUnknown V-table pointer" identifies the source of the COM reference.
0:019> dps 00007ffc33609078
00007ffc`33609078 00007ffc`33607cb0 nativerd!CONFIG_SYSTEM::QueryInterface
00007ffc`33609080 00007ffc`33605750 nativerd!CONFIG_SYSTEM::AddRef
00007ffc`33609088 00007ffc`33605700 nativerd!CONFIG_SYSTEM::Release
00007ffc`33609090 00007ffc`33627fe0 nativerd!CONFIG_SYSTEM::GetAdminSection
00007ffc`33609098 00007ffc`33603fb0 nativerd!CONFIG_SYSTEM::GetMetadata
00007ffc`336090a0 00007ffc`33609e40 nativerd!CONFIG_SYSTEM::SetMetadata
00007ffc`336090a8 00007ffc`3364fc30 nativerd!CONFIG_SYSTEM::get_ConfigManager
00007ffc`336090b0 00007ffc`3364ecc0 nativerd!CONFIG_SYSTEM::CommitChanges
00007ffc`336090b8 00007ffc`3363c7d0 nativerd!CONFIG_SYSTEM::get_CommitPath
00007ffc`336090c0 00007ffc`336235c0 nativerd!CONFIG_SYSTEM::put_CommitPath
00007ffc`336090c8 00007ffc`33626190 nativerd!CONFIG_SYSTEM::`vector deleting destructor'
00007ffc`336090d0 00007ffc`3362e780 nativerd!CONFIG_MAPPING_EXTENSION::QueryInterface
00007ffc`336090d8 00007ffc`33604730 nativerd!CONFIG_MAPPING_EXTENSION::AddRef
00007ffc`336090e0 00007ffc`33604190 nativerd!CONFIG_MAPPING_EXTENSION::Release
00007ffc`336090e8 00007ffc`336530c0 nativerd!CONFIG_MAPPING_EXTENSION::GetSiteNameFromSiteId
00007ffc`336090f0 00007ffc`33652e20 nativerd!CONFIG_MAPPING_EXTENSION::GetSiteIdFromSiteName
What is the difference between the !sos.dumprcw and !sosex.rcw output in regards to vtable?

Related

Get memory size and object count of Recycle Bin

I'm using Borland C++Builder 6 Enterprise on Windows 10.
I have the following code to extract the memory size and object count of the Recycle Bin:
...
#include "shellapi.h"
...
void __fastcall TForm6::Button10Click(TObject *Sender)
{
SHQUERYRBINFO rbinfo;
AnsiString sSize,
sCount;
int rc;
unsigned __int64 i64Size,
i64Cnt;
rbinfo.cbSize=sizeof(rbinfo);
rc=SHQueryRecycleBin("C:\\", &rbinfo);
if (rc!=S_OK)
Application->MessageBox( "Fehler bei SHQueryRecycleBin", "Fehler", MB_OK | MB_ICONERROR);
else
{
i64Size = rbinfo.i64Size;
i64Cnt = rbinfo.i64NumItems;
sSize =AnsiString(rbinfo.i64Size);
sCount=AnsiString(rbinfo.i64NumItems);
Application->MessageBox(sSize.c_str(), "Speicherplatz", MB_OK | MB_ICONINFORMATION);
Application->MessageBox(sCount.c_str(), "Anzahl Objekte", MB_OK | MB_ICONINFORMATION);
}
}
The function gets the total wrong values. The memory size is greater than disk space. The object count is 43628621390151600.
What am I doing wrong here?
Hello
I replace int to HRESULT.
The return values from the API function are already wrong.
rbinfo.i64Size=433791696898
sSize= 433791696898
rbinfo.i64NumItems=0
sCount =0
The tool Secure Eraser shows 206.195 files and 197.121,3 MB in Recycle
Bin. (picture)
The tool CCleaner shows 560 files (objects) and 36.441.834 KB in Recycle
Bin. (CCleaner.jpg)
In Windows Explorer there are also 560 objects in Recycle Bin.

Why does initializing this swift object produce an ARC of 2 instead of 1?

I was running into a problem in my project and I realized that an object is not being deallocated as needed. I decided to test the ARC of the object and just after initialization it is 2. In this trivial example below the same is true. Why is the ARC 2 and not 1?
import SpriteKit
class LevelBuilder:SKNode{
var testNode:SKSpriteNode?
init(with color:SKColor){
super.init()
self.testNode = SKSpriteNode(color: color, size: CGSize(width: 2, height: 2))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
let test = LevelBuilder(with: .red)
print("ARC: \(CFGetRetainCount(test))")
It prints ARC: 2
There is no such thing as "the ARC of the object." What you're thinking about is the retain count. It is hard to imagine a number more meaningless than the retain count. It is either zero (in which case the object is gone, so you'll never see that), or it is "not zero."
The retain count is the number of ownership claims that have been put on an object. Any part of the system is free to make an ownership claim at any time. Any part of the system can remove their ownership claim at any time. There's a whole thing called the autorelease pool that holds ownership claims and will automatically release those claims "at some point in the future." It is completely normal for an object to have several autorelease retains on it at any given time. That will increase the retain count, but the retain count will drop later.
If retain counts were meaningless under MRC (and they were), they're completely bonkers under ARC, where the compiler is free to optimize them out anytime it can prove it doesn't matter, and often injects extra retains when it can't prove they're not needed (particularly related to function calls). So the actual value is even more meaningless. For example, under ARC, it is completely appropriate for test to have an extra retain attached to it before calling CFGetRetainCount just to make sure that test isn't released too quickly.
If you have a memory management problem, you want to use tools like the memory graph debugger (and just looking for strong references and especially strong loops). Checking the retain count will only lie to you.
In your particular case, we can explore it a bit with swiftc -emit-sil, starting at the point that we do string interpolation (i.e. the "" in the last line):
// function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%34 = function_ref #$SSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $#convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, #thin String.Type) -> #owned String // user: %35
%35 = apply %34(%30, %31, %32, %33) : $#convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, #thin String.Type) -> #owned String // user: %37
%36 = alloc_stack $String // users: %39, %37, %41
store %35 to %36 : $*String // id: %37
// function_ref specialized String.init<A>(stringInterpolationSegment:)
%38 = function_ref #$SSS26stringInterpolationSegmentSSx_tcs23CustomStringConvertibleRzs20TextOutputStreamableRzlufCSS_Tg5 : $#convention(method) (#owned String, #thin String.Type) -> #owned String // user: %40
%39 = load %36 : $*String // user: %40
%40 = apply %38(%39, %29) : $#convention(method) (#owned String, #thin String.Type) -> #owned String // user: %42
dealloc_stack %36 : $*String // id: %41
store %40 to %28 : $*String // id: %42
%43 = integer_literal $Builtin.Word, 1 // user: %44
%44 = index_addr %28 : $*String, %43 : $Builtin.Word // user: %58
%45 = metatype $#thin String.Type // user: %56
%46 = load %3 : $*LevelBuilder // users: %48, %47
=========
strong_retain %46 : $LevelBuilder // id: %47
%48 = init_existential_ref %46 : $LevelBuilder : $LevelBuilder, $AnyObject // user: %49
%49 = enum $Optional<AnyObject>, #Optional.some!enumelt.1, %48 : $AnyObject // users: %52, %51
// function_ref CFGetRetainCount
%50 = function_ref #CFGetRetainCount : $#convention(c) (Optional<AnyObject>) -> Int // user: %51
%51 = apply %50(%49) : $#convention(c) (Optional<AnyObject>) -> Int // user: %54
release_value %49 : $Optional<AnyObject> // id: %52
=========
I've marked the important part with === lines. A strong retain is put on test. It's then wrapped up into a AnyObject? wrapper to pass to the C function (GetRetainCount). The function is called. And then the value of the Optional (i.e. test) is released. So you should expect one extra retain when you call GetRetainCount.
But if you re-compile this with -O, you'll notice that there is no strong_retain instruction. ARC sees that the extra retain isn't actually necessary and removes it. So that suggests that with optimization the retain count will be 1. I wonder if that's true:
$ swiftc main.swift
$ ./main
ARC: 2
$ swiftc -O main.swift
$ ./main
ARC: 1
Sure enough.
Maybe because you initialize your testNode which is a SKSpriteNode which might as well be referencing to SKNode under the hood. So you have first reference from your LevelBuilder class and the second one comes from the testNode.

InitializeSecurityContext and Delphi

I'm trying to use SSPI authentication to connect to Sql Server. There is working (I hope) C example with FreeTds sspi.c that using InitializeSecurityContext.
The problem is it calling InitializeSecurityContext twice. At first (tds_sspi_get_auth) function called to make auth to put it into login packet. There Service principal name (SPN) created as (Project JEDI JwaSspi used)
FSPN := WideString(Format('MSSQLSvc/%s:%d', [FHostName, FPort]));
status := InitializeSecurityContext(#FCred, nil, PSecWChar(FSPN),
ISC_REQ_CONFIDENTIALITY or ISC_REQ_REPLAY_DETECT or ISC_REQ_CONNECTION,
0, SECURITY_NETWORK_DREP, nil, 0, #FCredCtx, #desc, attrs, #ts);
where FSPN: WideString;
Second call (tds_sspi_handle_next) to InitializeSecurityContext uses same FSPN and response from server
status := InitializeSecurityContext(#FCred, #FCredCtx, PSecWChar(FSPN),
ISC_REQ_CONFIDENTIALITY or ISC_REQ_REPLAY_DETECT or ISC_REQ_CONNECTION,
0, SECURITY_NETWORK_DREP, #in_desc, 0, #FCredCtx, #out_desc, attrs, #ts);
Now hard part: on C SPN created with asprintf, after first call to InitializeSecurityContext it changed (was $4D $00 $53 $00 $53 $00 ... , after $08 $04 $01 $00 $4E ...) and I guess replaced by Digest or similar. By using like that I have Access Violation somewhere in oleaut32.dll.
It is "Project JEDI" bug. SecHandle declared as
_SecHandle = record
dwLower: ULONG_PTR;
dwUpper: ULONG_PTR;
end;
where
INT_PTR = Integer;
{$EXTERNALSYM INT_PTR}
PINT_PTR = ^INT_PTR;
{$EXTERNALSYM PINT_PTR}
UINT_PTR = Longword;
{$EXTERNALSYM UINT_PTR}
PUINT_PTR = ^UINT_PTR;
{$EXTERNALSYM PUINT_PTR}
LONG_PTR = Longint;
{$EXTERNALSYM LONG_PTR}
PLONG_PTR = ^LONG_PTR;
{$EXTERNALSYM PLONG_PTR}
ULONG_PTR = Longword;
{$EXTERNALSYM ULONG_PTR}
PULONG_PTR = ^ULONG_PTR;
{$EXTERNALSYM PULONG_PTR}
by Microsoft ULONG_PTR is
typedef unsigned __int3264 ULONG_PTR;
and
2.2.1 __int3264
An alias that is resolved to either:
An __int32 in a 32-bit translation and execution environment, or
An __int64 in a 64-bit translation and execution environment. For backward compatibility, it is 32-bit on the wire. The higher 4 bytes MUST be truncated on the sender side during marshaling and MUST be extended appropriately (signed or unsigned), as specified in [C706] section 14.2.5, on the receiving side during unmarshaling.
So when I declared in my class
private
FCred: CredHandle;
FCredCtx: CtxtHandle;
FSPN: WideString;
InitializeSecurityContext with 64 bit executable smashed my class variables by writing larger structure into FCredCtx ruining FSPN. Using NativeInt or NativeUInt instead of Integer/Longword etc fixed issue.

Using a ByteBuffer to represent a string in a JNA call results in extra characters in the buffer

I'm calling a dll using JNA and code generated using Jnaerator. One of the methods requires an string, and the JNA signature takes a ByteBuffer.
I've tried allocating the ByteBuffer as direct (ByteBuffer.allocateDirect) and indirect (ByteBuffer.wrap) but in both cases some times the string that reaches the dll has additional random characters (e.g. ReceiptÚeœ ). The original byte[] is there (receipt = 52 65 63 65 69 70 74) but as well a variable number of additional random bytes (01 da 65 9c 19). Randomly the string is correct, with no additional bytes.
I've tried the equivalent code using BridJ instead of JNA (the method signature takes then a Pointer name) and it in that case it works fine. Unfortunately I can't switch to BridJ because I need to use the com.sun.jna.platform.win32 classes, unless I can generate a BridJ replacement for those (https://stackoverflow.com/questions/31658862/jnaerator-bridj-user32-missing-methods)
Native declaration:
HRESULT extern WINAPI WFSOpen ( LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID,DWORD dwTraceLevel, DWORD dwTimeOut, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion, LPWFSVERSION lpSPIVersion, LPHSERVICE lphService);
JNAerator JNA code:
//works
#Deprecated
NativeLong WFSOpen(Pointer lpszLogicalName, Pointer hApp, Pointer lpszAppID, int dwTraceLevel, int dwTimeOut, int dwSrvcVersionsRequired, WFSVERSION lpSrvcVersion, WFSVERSION lpSPIVersion, ShortByReference lphService);
//does not work
NativeLong WFSOpen(ByteBuffer lpszLogicalName, Pointer hApp, ByteBuffer lpszAppID, int dwTraceLevel, int dwTimeOut, int dwSrvcVersionsRequired, WFSVERSION lpSrvcVersion, WFSVERSION lpSPIVersion, ShortBuffer lphService);
Java call working (but deprecated)
Pointer m = new Memory(string.length() + 1); // WARNING: assumes ascii-only string
m.setString(0, string);
MsxfsLibrary.INSTANCE.WFSOpen(lpszLogicalName, lphApp.getValue(), lpszAppID, dwTraceLevel, dwTimeOut, dwSrvcVersionsRequired, lpSrvcVersion, lpSPIVersion, lphService);
Java call NOT working test A:
lpszLogicalName = ByteBuffer.wrap(bytes);
MsxfsLibrary.INSTANCE.WFSOpen(lpszLogicalName, lphApp.getValue(), lpszAppID, dwTraceLevel, dwTimeOut, dwSrvcVersionsRequired, lpSrvcVersion, lpSPIVersion, lphService);
Java call NOT working test B:
byte[] bytes = string.getBytes();
return ByteBuffer.wrap(bytes);
ByteBuffer bb = ByteBuffer.allocateDirect(bytes.length);
bb.put(bytes);
lpszLogicalName = bb.position(0);
msxfsLibrary.WFSOpen(lpszLogicalName, lphApp.getValue(), lpszAppID, dwTraceLevel, dwTimeOut, dwSrvcVersionsRequired, lpSrvcVersion, lpSPIVersion, lphService);
If you're referring to _wfsopen(), it's expecting a wide-character string. Either use WString, or configure your library to type-map String (see W32APIOptions.UNICODE_OPTIONS).
I think what's happening is that you are passing an array of bytes that contains your string but it is not null terminated string. You should create a byte array with an extra position. Set that las position to 0 and copy your string into that byte array.

How to call a Delphi DLL from VB6

Given the following Delphil DLL declaration
function csd_HandleData(aBuf: PChar; aLen: integer): integer; stdcall;
what would be the VB6 declaration to use it?
I've tried a variety of declarations, e.g.
Declare Function csd_HandleData Lib "chsdet.dll" (ByVal aBuf As String, ByVal aLen As Integer)
Declare Function csd_HandleData Lib "chsdet.dll" (aBuf As Long, ByVal aLen As Integer)
Declare Function csd_HandleData Lib "chsdet.dll" (aBuf As Byte, ByVal aLen As Integer)
with the relevant code to suit the parameters, but nothing seems to work, i.e. the Delphi debugger says I have a too-largish value in aLen and a null string in aBuf.
I am working toward using a TypeLib to drive the connection, but was prototyping with Declares.
try
Declare Function csd_HandleData Lib "chsdet.dll" (ByVal aBuf As String,
ByVal aLen As Integer) As Integer
Seems you forgot the return value.
VB integer datatype is 16bit, so you should declare it as long which is equivalent to integer in Delphi and other languages.
Declare Function csd_HandleData Lib "chsdet.dll" (ByVal aBuf As String, ByVal aLen As long) as long
For those interested, here's the final IDL for the typelib for CHSDET. What impressed me (after re-discovering Matt Curland's EditTLB tool) was that I can put structures into a typelib, and VB handles them as if I'd declared them in the source code.
I've written to the author of ChsDet and perhaps this will end up as part of the standard distro.
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: chsdet.tlb
[
uuid(316A83D7-8BF4-490E-BDDE-75EBC332C355),
version(1.0),
helpstring("Charset Detector - as the name says - is a stand alone executable module for automatic charset detection of a given text.\r\n\t\r\nIt can be useful for internationalisation support in multilingual applications such as web-script editors or Unicode editors.\r\n\t\r\nGiven input buffer will be analysed to guess used encoding. The result can be used as control parameter for charset conversation procedure.\r\n\t\r\nCharset Detector can be compiled (and hopefully used) for MS Windows (as dll - dynamic link library) or Linux.\r\n\t\r\nBased on Mozilla's i18n component - http://www.mozilla.org/projects/intl/. \r\n\r\nCharset Detector is open source project and distributed under Lesser GPL.\r\nSee the GNU Lesser General Public License for more details - http://www.opensource.org/licenses/lgpl-license.php\r\n\r\nNikolaj Yakowlew \xFFFFFFA9 2006-2008 \r\nTypeLib by Bruce M. Axtens, 2008.")
]
library CHSDET
{
// TLib : // Forward declare all types defined in this typelib
[
dllname("CHSDET.dll"),
version(1.0),
helpstring("Functions in CHSDET.DLL")
]
module CHSDETFunctions {
[entry(0x60000000), helpstring("Returns rAbout record (qv)")]
void _stdcall GetAbout([in, out] rAbout* AboutRec);
[entry(0x60000001), helpstring("Reset detector. Prepares for new analysis.")]
void _stdcall Reset();
[entry(0x60000002), helpstring("Analyse given buffer of specified length.
Return value is of eHandleDataErrors, either
NS_ERROR_OUT_OF_MEMORY (Unable to create internal objects) or NS_OK.
Function can be called more that one time to continue guessing. Charset Detector remembers last state until Reset called.")]
void _stdcall HandleData(
[in] BSTR aBuf,
[in] short aLen,
[out, retval] short* retVal);
[entry(0x60000003), helpstring("Returns either TRUE (Charset Detector is sure about text encoding.) or FALSE.
NB: If input buffer is smaller then 1K, Charset Detector returns FALSE.")]
void _stdcall IsDone([out, retval] short* retVal);
[entry(0x60000004), helpstring("Signal data end. If Charset Detector hasn't sure result (IsDone = FALSE) the best guessed encoding will be set as result.")]
void _stdcall DataEnd();
[entry(0x60000005), helpstring("Returns guessed charset as rCharsetInfo record")]
void _stdcall GetDetectedCharset([out, retval] rCharsetInfo* retVal);
[entry(0x60000006), helpstring("Returns all supported charsets in form "0x0A Name - CodePage"")]
void _stdcall GetKnownCharsets(
[in, out] long* sList,
[out, retval] long* retVal);
[entry(0x60000007), helpstring("Return eBOMKind value matching byte order mark (if any) of input data.")]
void _stdcall GetDetectedBOM([out, retval] eBOMKind* retVal);
[entry(0x60000008), helpstring("Remove CodePage from consideration as a possible match")]
void _stdcall DisableCharsetCP([in] long CodePage);
};
typedef [uuid(91694067-30AB-44A9-A210-F5602935475F)]
struct tagrAbout {
long lMajor;
long lMinor;
long lRelease;
long sAbout;
} rAbout;
typedef [uuid(3C8B7420-D40B-458B-8DE8-9B3D28607396)]
enum {
BOM_Not_Found = 0,
BOM_UCS4_BE = 1,
BOM_UCS4_LE = 2,
BOM_UCS4_2143 = 3,
BOM_UCS4_3412 = 4,
BOM_UTF16_BE = 5,
BOM_UTF16_LE = 6,
BOM_UTF8 = 7
} eBOMKind;
typedef [uuid(9B231DEF-93FB-440D-B06B-D760AECE09D0)]
struct tagrCharsetInfo {
long Name;
short CodePage;
long Language;
} rCharsetInfo;
typedef enum {
NS_OK = 0,
NS_ERROR_OUT_OF_MEMORY = -2147024882
} eHandleDataErrors;
};
I don't know what a PChar is in Delphi, is it just one character? ASCII?? Unicode?
An Integer is 16 bits in VB6, you'll have to declare aLen as Long, which can hold 32 bits.
You also have to declare the return type of the function, in this case you'll want to return a Long value too.
This will probably work:
Declare Function csd_HandleData Lib "chsdet.dll" (aBuf As Byte, ByVal aLen As Long) As Long
I don´t know exactly how Vb works but PChar is a pointer, so try to get the reference instead of the value.
Declare Function csd_HandleData Lib "chsdet.dll" (**ByReference <--guessing here :D** aBuf As String, ByVal aLen As Integer)

Resources