注册 登录
编程论坛 VFP论坛

围观一下高手如何在VFP中处理C语言的结构体(struct)

cssnet 发布于 2023-08-22 11:01, 495 次点击
* ----------------------------
* 这是从VFPX中复制的一段代码,功能是:调用comdlg32中的“保存文件”系统对话框。
* 当中自定义的PChar类,很有意思,通过它来轻松操作struct中需要用到的字段。
* ----------------------------
DO decl

* some of the bit flags for the dialog
#DEFINE OFN_HIDEREADONLY 4
#DEFINE OFN_NOCHANGEDIR 8
#DEFINE OFN_EXTENSIONDIFFERENT 0x400
#DEFINE OFN_PATHMUSTEXIST 0x800
#DEFINE OFN_CREATEPROMPT 0x2000
#DEFINE OFN_EXPLORER 0x80000
#DEFINE OFN_DONTADDTORECENT 0x2000000

*| typedef struct tagOFN {
*|   DWORD         lStructSize;      0:4
*|   HWND          hwndOwner;        4:4
*|   HINSTANCE     hInstance;        8:4
*|   LPCTSTR       lpstrFilter;     12:4
*|   LPTSTR        lpstrCustFilt;   16:4
*|   DWORD         nMaxCustFilter;  20:4
*|   DWORD         nFilterIndex;    24:4
*|   LPTSTR        lpstrFile;       28:4
*|   DWORD         nMaxFile;        32:4
*|   LPTSTR        lpstrFileTitle;  36:4
*|   DWORD         nMaxFileTitle;   40:4
*|   LPCTSTR       lpstrInitialDir; 44:4
*|   LPCTSTR       lpstrTitle;      48:4
*|   DWORD         Flags;           52:4
*|   WORD          nFileOffset;     56:2
*|   WORD          nFileExtension;  58:2
*|   LPCTSTR       lpstrDefExt;     60:4
*|   LPARAM        lCustData;       64:4
*|   LPOFNHOOKPROC lpfnHook;        68:4
*|   LPCTSTR       lpTemplateName;  72:4 = 76 bytes
*| #if (_WIN32_WINNT >= 0x0500)
*|   void *        pvReserved;      76:4
*|   DWORD         dwReserved;      80:4
*|   DWORD         FlagsEx;         84:4
*| #endif // (_WIN32_WINNT >= 0x0500)
*| } OPENFILENAME, *LPOPENFILENAME; total = 88 bytes

#DEFINE OPENFILENAME_SIZE  76  && set to 88 for W2K

LOCAL lcBuffer, loFilter, loFilename, loFilenameRet,;
    loTitlebar, loDefExt, lnFlags, lnFileOffset, lnExtOffset,;
    lcFullname, lcPath, lcFilename, lcFileext

loFilter = CreateObject("PChar",;
    "Text Files" + Chr(0) + "*.txt;*.bak" + Chr(0)+Chr(0))

loFilename = CreateObject("PChar", Padr("myfile.txt", 250,Chr(0)))

loFilenameRet = CreateObject("PChar", Repli(Chr(0),250))

loTitlebar = CreateObject("PChar",;
    "Will you save this file at least?")

loDefExt = CreateObject("PChar", "TXT")

lnFlags = OFN_PATHMUSTEXIST + OFN_EXTENSIONDIFFERENT +;
    OFN_CREATEPROMPT + OFN_HIDEREADONLY + OFN_NOCHANGEDIR

* compiling the OPENFILENAME structure
* Rem: initdir - default chosen

lcBuffer = num2dword(OPENFILENAME_SIZE) +;
    num2dword(GetActiveWindow()) +;
    num2dword(0) +;
    num2dword(loFilter.GetAddr()) +;
    num2dword(0) +;
    num2dword(0) +;
    num2dword(1) +;
    num2dword(loFilename.GetAddr()) +;
    num2dword(loFilename.GetAllocSize()) +;
    num2dword(loFilenameRet.GetAddr()) +;
    num2dword(loFilenameRet.GetAllocSize()) +;
    num2dword(0) +;
    num2dword(loTitlebar.GetAddr()) +;
    num2dword(lnFlags) +;
    num2dword(0) +;
    num2dword(loDefExt.GetAddr()) +;
    num2dword(0) +;
    num2dword(0) +;
    num2dword(0)

* creating a Save dialog box using the prepared structure

IF GetSaveFileName (@lcBuffer) = 0
    LOCAL lnErrorCode
    lnErrorCode = CommDlgExtendedError()
    IF lnErrorCode <> 0
        ? "Error code:", lnErrorCode
    ELSE
    * the Cancel button selected
    ENDIF

ELSE
    lcFullname = STRTRAN(Trim(loFilename.GetValue()), Chr(0),"")
    lcFilename = STRTRAN(Trim(loFilenameRet.GetValue()), Chr(0),"")

    lnFileOffset = buf2word(SUBSTR(lcBuffer, 57,2))
    lnExtOffset = buf2word(SUBSTR(lcBuffer, 59,2))

    lcPath = SUBSTR(lcFullname, 1, lnFileOffset-1)
    lcFileext = SUBSTR(lcFullname, lnExtOffset+1)

    ? lcFullname
    ? lcPath
    ? lcFilename
    ? lcFileext
ENDIF
* end of main

FUNCTION  num2dword (lnValue)
RETURN BINTOC(lnValue, "4RS")
#if .f.
    *---------------
    * 注:老外原函数太过冗长,顺手改为上边的一句话搞定。
    #DEFINE m0       256
    #DEFINE m1     65536
    #DEFINE m2  16777216
        LOCAL b0, b1, b2, b3
        b3 = Int(lnValue/m2)
        b2 = Int((lnValue - b3*m2)/m1)
        b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
        b0 = Mod(lnValue, m0)
    RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)
    *---------------
#endif .f.

FUNCTION  buf2word (lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
    Asc(SUBSTR(lcBuffer, 2,1)) * 256

DEFINE CLASS PChar As Custom
    PROTECTED hMem

PROCEDURE  Init (lcString)
    THIS.hMem = 0
    THIS.setValue (lcString)

PROCEDURE  Destroy
    THIS.ReleaseString

FUNCTION getAddr  && returns a pointer to the string
RETURN THIS.hMem

FUNCTION getValue && returns string value
    LOCAL lnSize, lcBuffer
    lnSize = THIS.getAllocSize()
    lcBuffer = SPACE(lnSize)

    IF THIS.hMem <> 0
        DECLARE RtlMoveMemory IN kernel32 As Heap2Str;
            STRING @, INTEGER, INTEGER
        = Heap2Str (@lcBuffer, THIS.hMem, lnSize)
    ENDIF
RETURN lcBuffer

FUNCTION getAllocSize  && returns allocated memory size (string length)
    DECLARE INTEGER GlobalSize IN kernel32 INTEGER hMem
RETURN Iif(THIS.hMem=0, 0, GlobalSize(THIS.hMem))

PROCEDURE setValue (lcString) && assigns new string value
#DEFINE GMEM_FIXED   0
    THIS.ReleaseString

    DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER, INTEGER
    DECLARE RtlMoveMemory IN kernel32 As Str2Heap;
        INTEGER, STRING @, INTEGER

    LOCAL lnSize
    lcString = lcString + Chr(0)
    lnSize = Len(lcString)
    THIS.hMem = GlobalAlloc (GMEM_FIXED, lnSize)
    IF THIS.hMem <> 0
        = Str2Heap (THIS.hMem, @lcString, lnSize)
    ENDIF

PROCEDURE ReleaseString  && releases allocated memory
    IF THIS.hMem <> 0
        DECLARE INTEGER GlobalFree IN kernel32 INTEGER
        = GlobalFree (THIS.hMem)
        THIS.hMem = 0
    ENDIF
ENDDEFINE

PROCEDURE  decl
    DECLARE INTEGER GetActiveWindow IN user32
    DECLARE INTEGER GlobalFree IN kernel32 INTEGER hMem
    DECLARE INTEGER GetSaveFileName IN comdlg32 STRING @lpofn
    DECLARE INTEGER CommDlgExtendedError IN comdlg32  
4 回复
#2
kangss2023-08-22 15:19
我记得版主去年专门讲过结构体的几种方法,你搜索一下。
#3
iswith2023-08-22 21:01
个人觉得结构这玩意还是c32最好用,最直观!其它说实话维护代码起来真麻烦!
#4
自强不西2023-09-07 13:50
都是高手!
#5
sam_jiang2023-09-07 15:06


[此贴子已经被作者于2023-9-7 15:15编辑过]

1