回复 39楼 csyx
可以试试用打开文件名对话框那个api只显示文件夹做打开文件夹对话框
** ** StructCalss_DirDialog.prg ** #INCLUDE StructCalss.h SET PROCEDURE TO StructCalss.prg ADDITIVE LoadApi() ? myGetDir("c:\temp\test") SET PROCEDURE TO CLEAR ALL RETURN FUNCTION myGetDir(cDefDir) LOCAL bi, fa, pDir, pDefDir, cDir, pci, pit pDir = apiMalloc(MAX_PATH) pDefDir = myStrptr(cDefDir) fa = CREATEOBJECT("FUNCTIONADDRESS") bi = CREATEOBJECT("BROWSEINFOA") bi.setValue("pszDisplayName", pDir) bi.setValue("lpfn", fa.GetFunAddr("CallbackProc",4)) bi.setValue("lParam", pDefDir) pit = apiSHBrowseForFolder(bi.pBuffer) cDir = "" IF pit > 0 apiSHGetPathFromIDList(pit, pDir) cDir = SYS(2600, pDir, apiStrlen(pDir)) apiCoTaskMemFree(pit) ENDIF apiFree(pDefDir) apiFree(pDir) RETURN cDir ENDFUNC ** 回调函数 FUNCTION CallbackProc(hWnd, Msg, wParam, lParam) IF Msg == BFFM_INITIALIZED * BFFM_SETSELECTIONA 消息自动选择初始路径 apiSendMessage(hWnd, BFFM_SETSELECTIONA, BFFM_INITIALIZED, lParam) ENDIF RETURN 0 ENDFUNC * 获取调用VFP函数的函数指针 DEFINE CLASS FUNCTIONADDRESS as Session DIMENSION aPFunction[1] hUser32 = 0 fMessageBox = 0 pMsg = 0 pTitle = 0 hMSvcrt = 0 fSwprintf = 0 hOleaut32 = 0 fSysAllocString = 0 fSysFreeString = 0 pFunName = 0 PROCEDURE Init this.hUser32 = apiLoadLibrary("user32.dll") this.fMessageBox = apiGetProcAddress(this.hUser32, "MessageBoxA") this.pMsg = myStrptr("调用 FUNCTIONADDRESS 类 GetFunAddr() 失败") this.pTitle = myStrptr("提示") this.hMSvcrt = apiLoadLibrary("msvcrt.dll") this.fSwprintf = apiGetProcAddress(this.hMSvcrt, "swprintf") this.hOleaut32 = apiLoadLibrary("oleaut32.dll") this.fSysAllocString = apiGetProcAddress(this.hOleaut32, "SysAllocString") this.fSysFreeString = apiGetProcAddress(this.hOleaut32, "SysFreeString") ENDPROC PROCEDURE Destroy LOCAL pf FOR EACH pf IN this.aPFunction apiFree(pf) ENDFOR apiFree(this.pMsg) apiFree(this.pTitle) apiFree(this.pFunName) apiFreeLibrary(this.hUser32) apiFreeLibrary(this.hMSvcrt) apiFreeLibrary(this.hOleaut32) ENDPROC FUNCTION GetFunAddr(cFunName, nParameters) && 函数名,参数个数 LOCAL nCount, cCode, cMsgCode IF EMPTY(cFunName) RETURN 0 ENDIF * 格式:函数名(%d,%d,......%d,%d) cFunName = STRCONV(cFunName + "(%d" + REPLICATE(",%d", nParameters - 1) + ")"+0h00, 5) this.pFunName = myStrptr(cFunName) * 出错提示 cMsgCode = "" cMsgCode = cMsgCode + 0h6A00 && push 0 MessageBox()第4个参数 cMsgCode = cMsgCode + 0h68 + BINTOC(this.pTitle,"4RS") && push pTitle MessageBox()第3个参数 cMsgCode = cMsgCode + 0h68 + BINTOC(this.pMsg, "4RS") && push pMsg MessageBox()第2个参数 cMsgCode = cMsgCode + 0h6A00 && push 0 MessageBox()第1个参数 cMsgCode = cMsgCode + 0hB8 + BINTOC(this.fMessageBox,"4RS") && move eax, fMessageBox cMsgCode = cMsgCode + 0hFFD0 && call MessageBox cMsgCode = cMsgCode + 0hB801000000 && mov eax,00000001h 返回1(.T.) * * 函数的二进制代码 * * 保存栈顶指针 ebp <- esp, 调整栈顶指针esp <- (esp-2000)预留足够栈空间 cCode = 0h55 && PUSH EBP 保存ebp cCode = cCode + 0h8BEC && MOV EBP,ESP 栈顶指针保存到ebp作为栈基址 cCode = cCode + 0h81EC + BINTOC(2000, "4RS") && SUB ESP,000007D0h 预留2000字节足够栈空间 * swprintf(pOut, "<VFP函数名>(%d,%d,...,%d,%d)", ect1, ect2,..., ectn-1, ectn) * 调用swprintf(pOut, pFmt, ect),将输出参数 pOut 的内容作为VFP函数表达式 * pOut,输出,指向VFP函数表达式的指针, 表达式: "<VFP函数名>(<数值1>,<数值2>,...,<数值n>)" * pFmt,输入,指向VFP函数格式字符串的指针, 表达式: "<VFP函数名>(%d,%d,...,%d)" * ect, 输入,参数表,<数值1>,<数值2>,...,<数值n> * * 函数的输入参数作为swprintf()的ect参数,输出转换为VFP函数的输入参数 * 参数入栈代码 FOR i = nParameters TO 1 STEP -1 cCode = cCode; + 0h8B45 + CHR(4 + i * 4); + 0h50 ENDFOR * ectn * ...... ectn-1 * * 0h8B450C && MOV EAX, DWORD PTR [EBP+0C] ect2 * 0h50 && PUSH EAX * 0h8B4508 && MOV EAX, DWORD PTR [EBP+08] ect1 * 0h50 && PUSH EAX cCode = cCode + 0hB8 + BINTOC(this.pFunName, "4RS") && MOV EAX, pVFP函数 pFmt cCode = cCode + 0h50 && PUSH EAX cCode = cCode + 0h8D45A0 && LEA EAX, [EBP-60h] pOut cCode = cCode + 0h50 && PUSH EAX cCode = cCode + 0hB8 + BINTOC(this.fSwprintf, "4RS") && MOV EAX, fSwprintf cCode = cCode + 0hFFD0 && CALL EAX 调用swprintf() * 因 swfprintf() 不会自动恢复堆栈指针 * esp 恢复到调用swfprintf()前状态,esp <- esp + (n参数个数+2)*4) cCode = cCode + 0h83C4 + CHR((nParameters + 2) * 4) && ADD ESP,(n参数个数+2)*4) * [EBP-10h] = SysAllocString([EBP-60h]) * 调用SysAllocString()将VFP函数表达式字符串转换成BSTR字符串 cCode = cCode + 0h8D45A0 && LEA EAX,[EBP-60h] 指向VFP函数表达式字符串指针 cCode = cCode + 0h50 && PUSH EAX 作为SysAllocString()输入参数 cCode = cCode + 0hB8 + BINTOC(this.fSysAllocString, "4RS") && MOV EAX, fSysAllocString cCode = cCode + 0hFFD0 && CALL EAX 调用SysAllocString() * 保存SysAllocString()返回的BSTR字符串指针,之后由SysFreeString()释放 cCode = cCode + 0h8945F0 && MOV [EBP-10h],EAX * _VFP.DoCmd(<VFP函数表达式>) * 转换成BSTR字符串的VFP函数表达式, 作为调用_VFP对象DoCmd方法的输入参数 cCode = cCode + 0h50 && PUSH EAX cCode = cCode + 0hB8 + BINTOC(SYS(3095, _VFP), "4RS") && MOV EAX, SYS(3095, _VFP) 获取_VFP对象的IDispatch指针 cCode = cCode + 0h50 && PUSH EAX _VFP指针 cCode = cCode + 0h8B00 && MOV EAX,[EAX] 获取_VFP的函数表指针 cCode = cCode + 0h0584000000 && ADD EAX,00000084h _函数表指针偏移 84h 是_VFP.DoCmd函数的指针 cCode = cCode + 0hFF10 && CALL [EAX] 调用_VFP.DoCmd(<VFP函数表达式>) **cCode = cCode + 0hB800000000 && MOV EAX,00000000h eax <- 0 (DoCmd()返回NULL) * 是否成功返回0 cCode = cCode + 0h83F800 && CMP EAX, 0 * 是,成功返回,跳过出错提示。 cCode = cCode + 0h74 + CHR(LEN(cMsgCode)) && je len(cMsgCode), je=0h74(等于), jne=0h75(不等于) cCode = cCode + cMsgCode && 出错提示代码 * SysFreeString([EBP-10h]) * 释放由SysAllocString()分配生成BSTR字符串的空间 cCode = cCode + 0h8B45F0 && MOV EAX,[EBP-10h] cCode = cCode + 0h50 && PUSH EAX cCode = cCode + 0hB8 + BINTOC(this.fSysFreeString, "4RS") && MOV EAX, fSysFreeString cCode = cCode + 0hFFD0 && CALL EAX 调用SysFreeString() cCode = cCode + 0hB801000000 && MOV EAX,00000001h 返回1(.T.) **cCode = cCode + 0hB800000000 && MOV EAX,00000000h 返回0(.F.) cCode = cCode + 0h8BE5 && MOV ESP,EBP 恢复栈顶指针 cCode = cCode + 0h5D && POP EBP 恢复ebp * 返回,按“堆栈平衡”原则,被调用者把堆栈指针修正到调用前的状态。 * RET n参数个数*4,即 esp <- (esp + n参数个数*4),因调用者首先把参数压入堆栈 cCode = cCode + 0hC2 + BINTOC(nParameters * 4, "4RS") && RET n参数个数*4 nCount = ALEN(this.aPFunction) + IIF(!EMPTY(this.aPFunction[1]), 1, 0) DIMENSION this.aPFunction[nCount] && 函数指针数组 this.aPFunction[nCount] = apiMalloc(LEN(cCode)) && 分配函数代码内存空间 SYS(2600, this.aPFunction[nCount], LEN(cCode), cCode) && 载入函数代码 RETURN this.aPFunction[nCount] && 返回函数指针 ENDFUNC ENDDEFINE
[此贴子已经被作者于2022-3-20 14:57编辑过]
[此贴子已经被作者于2022-3-19 20:26编辑过]
CLEAR SET TALK OFF SET SAFETY OFF CLEAR ALL cDefPath = ADDBS(JUSTPATH(SYS(16))) SET DEFAULT TO (cDefPath) ** ** test.prg ** SET PROCEDURE TO apiFuns.prg ADDITIVE LoadApi() DECLARE integer CopyFileEx in Kernel32 string lpExistingFileName, string lpNewFileName,long lpProgressRoutine,long lpData,long pbCancel,long dwCopyFlags DECLARE integer EnumChildWindows IN WIN32API integer hWnd, long lpEnumProc, long lParam DECLARE Integer EnumFontFamilies IN gdi32 As EnumFontFamiliesA Integer hdc ,String lpszFamily ,Integer lpEnumFontFamProc,Integer lParam DECLARE INTEGER GetDC IN WIN32API INTEGER hwnd fa = CREATEOBJECT("FUNCTIONADDRESS") pCallBackMyWindow=fa.GetFunAddr('MyWindow', 2) pCallBackFontProc=fa.GetFunAddr('FontProc', 4) pCallBackCopyProc=fa.GetFunAddr('CopyProc', 9) EnumFontFamiliesA(GetDC(_vfp.hWnd),NULL,pCallBackFontProc,0) EnumChildWindows(_vfp.hWnd,pCallBackMyWindow,0) pbCancel=0 nRet=0 nRet=CopyFileEx("c:\temp\tmp.txt", "c:\temp\tmp2.txt", pCallBackCopyProc, 0, @pbCancel, 0) SET PROCEDURE TO CLEAR ALL RETURN Function CopyProc lparameters TotalFileSize, TotalBytesTransferred,StreamSize, StreamBytesTransferred,StreamNumber,CallbackReason,SourceFile,DestinationFile,lpData ?TotalFileSize, TotalBytesTransferred, ; StreamSize, StreamBytesTransferred, ; StreamNumber, ; CallbackReason, ; SourceFile, ; DestinationFile, ; lpData return 0 ENDFUNC FUNCTION MyWindow lparameters hwnd,lparam ?hwnd return 1 ENDFUNC FUNCTION FontProc lparameters lpelfe as long,lpntme as long,fonttype as integer, lparam as long *!*?lpelfe,lpntme,fonttype,lparam logfont=sys(2600,lpelfe,28+33) newtextmetric=sys(2600,lpntme,17*4+1) facename=alltrim(right(logfont,33)) facename=substr(facename,1,at(0h00,facename)-1) ? facename return 1 ENDFUNC