有个思路,在vc6里验证了一下,你整理一下应该可用
测试程序
#include "stdafx.h"
#include <windows.h>int CallDllFun(char *pDllPath, char *pFunName, BYTE *pParam, int nSize, BOOL bHaveRetVal)
{
    HINSTANCE hInst;
    hInst = LoadLibrary(pDllPath);
    typedef void (*ADDPROC)();
    ADDPROC PROC = (ADDPROC)GetProcAddress(hInst, pFunName);
    
    for (int i = nSize - 1; i >= 0; i--)
    {
        int k = *(int *)(&pParam[i * 4]);
        _asm
        {
            push k
        }
    }
    
    PROC();
    
    if (bHaveRetVal)
    {
        int nRet;
        _asm
        {
            mov nRet, eax
        }
        return nRet;
    }
    return 0;
    
}int main(int argc, char* argv[])
{
    char *pDllPath = "E:\\Work\\CCB\\dev_bp\\testdll111\\Release\\testdll111.dll";
    char *pFun1 = "Fun1";
    char *pFun2 = "Fun2";
    
    BYTE pParam[255] = "";
    char *pszParam = "asdfasdf";
    // 调用EXPORT1 int CALLBACK Fun1(char *pszParam)
    memcpy(pParam, &pszParam, 4);   // 第一个参数
    
    int nRet = CallDllFun(pDllPath, pFun1, pParam, 1, TRUE);
    
    int ch = 'A';       
    memcpy(pParam , &ch, 4);        // 第一个参数char类型
    int nVal = 1002;
memcpy(pParam + 4, &nVal, 4);   // 第二个参数
    nRet = CallDllFun(pDllPath, pFun2, pParam, 2, FALSE);
    return 0;
}Dll:
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#ifdef __cplusplus
#define EXPORT1 extern "C" __declspec (dllexport)
#else
#define EXPORT1 __declspec (dllexport)
#endifEXPORT1 int CALLBACK Fun1(char *pszParam)
{
    printf("%s\n", pszParam);
    return 0;
}EXPORT1 void CALLBACK Fun2(char ch, int nParam)
{
    printf("%c%d\n", ch, nParam);
    return;
}#pragma comment(linker, "/EXPORT:Fun1=_Fun1@4,PRIVATE")
#pragma comment(linker, "/EXPORT:Fun2=_Fun2@8,PRIVATE")
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    return TRUE;
}

解决方案 »

  1.   

    返回值有些问题,修正了的如下
    int CallDllFun(char *pDllPath, char *pFunName, BYTE *pParam, int nSize, BOOL bHaveRetVal)
    {
        int nRet;
        HINSTANCE hInst;
        hInst = LoadLibrary(pDllPath);
        typedef void (*ADDPROC)();
        ADDPROC PROC = (ADDPROC)GetProcAddress(hInst, pFunName);
        
        for (int i = nSize - 1; i >= 0; i--)
        {
            int k = *(int *)(&pParam[i * 4]);
            _asm
            {
                push k
            }
        }
        
        PROC();
        _asm
        {
            mov nRet, eax
        }   
        if (bHaveRetVal)
        {
            return nRet;
        }
        return 0;
        
    }
      

  2.   

    1。小心Calling Convention。 楼主的定义是 C Calling Convention,你的Code假设Pascal Calling Convention,这样回来后Stack会Corrupt掉。应该加个参数,如果是cdecl 的话,把参数从Stack上pop 出去  (或者直接add esp);2. 检查GetProcAddress的返回值,否则如果返回NULL后面就崩了。
      

  3.   

    可以参照wsprintf的格式编写。使用不定参数个数来完成。
      

  4.   

    感谢大家回复.shizhen的代码在运行时确实会因为Calling Convention问题崩溃.请教各位应如何修改.feimingbiao能给出具体代码吗?谢谢
      

  5.   

    exe和dll都用Release编译 Debug不知为何崩溃
      

  6.   

    Debug崩溃是由于函数返回值引起的 好像Debug模式在exe里加入了检测stack的代码
      

  7.   

    Debug模式有检查Esp的代码,Release模式虽然没有,但是Stack已经Corrupt了,早晚要出大事情,改成这样:偷段儿Shizen的程序,改成这个样子,DWORD CallDllFun(char *pDllPath, char *pFunName, BYTE *pParam, int nSize, int *pRetVal, BOOL bCCallingConvention)
    {
        HINSTANCE hInst;
        int nRet;
        hInst = LoadLibrary(pDllPath);
        typedef void (*ADDPROC)();
        ADDPROC PROC = (ADDPROC)GetProcAddress(hInst, pFunName);    //
        // Make sure GetProcAddress succeed, otherwise will crash later
        //
        if (!PROC)
        {
            return GetLastError();  //ERROR_NOT_FOUND most likely.
        }
        
        for (int i = nSize - 1; i >= 0; i--)
        {
            int k = *(int *)(&pParam[i * 4]);
            _asm
            {
                push k
            }
        }
        
        PROC();
     
        //Save the eax value first, we are going to use it next.
         _asm 
        {
           mov nRet, eax
        }
        
        //
        // If API is of C calling convention, we need to clear the stack
        //
        if (bCCallingConvention)
        {
           __asm
           {
               mov eax, nSize;// 32bit system, argument * 4 should be the size to adjust
               shl eax, 2;
               add esp, eax;
           }
        }    if (pRetVal)
        {
            *pRetVal = nRet;
        }    return ERROR_SUCCESS;
        
    }我没有测试,你试一下。调用后需要检查返回值,如果不是ERROR_SUCCESS,说明失败了。API本身的返回值通过pRetVal得到。你的情况,bCCallingConvention给TRUE,如果你的函数前面有定义WINAPI或者__stdcall等等,这个传入FALSE。另外这段程序64位OS会有问题,我懒得该了,(Itaninum上根本不编译,因为用了386的汇编)。
      

  8.   

    for   (int   i   =   nSize   -   1;   i   >=   0;   i--) 
            { 
                    int   k   =   *(int   *)(&pParam[i   *   4]); 
                    _asm 
                    { 
                            push   k 
                    } 
            } 这是不是假设了参数都是int,问题是只有运行时才知道参数是什么类型啊
      

  9.   

    楼上没认真看贴EXPORT1   int   CALLBACK   Fun1(char   *pszParam) 

            printf("%s\n",   pszParam); 
            return   0; 
    } EXPORT1   void   CALLBACK   Fun2(char   ch,   int   nParam) 

            printf("%c%d\n",   ch,   nParam); 
            return; 
    } 三种类型的参数都有了
    我想32位编译器会把8位的char扩展到32位,一个寄存器的大小