Advertisement

help with directx

Started by July 24, 2002 02:43 AM
21 comments, last by oni_viper 22 years, 5 months ago
i''ve spent the last couple months trying to use directx. and failed miserably. i''ve tried every example i could find with no success (compiling errors). when i finally find a program with no compiling errors to fix, i then run into a whole new set of errors. linking errors... whenever i execute the program i get these errors: Linking... ddex2.obj : error LNK2001: unresolved external symbol _DirectDrawCreateEx@16 ddex2.obj : error LNK2001: unresolved external symbol _IID_IDirectDraw7 LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main Debug/ddex2.exe : fatal error LNK1120: 3 unresolved externals Error executing link.exe. my first guess is that the paths are incorrect. so i opened up DXSETENV.BAT and changed the paths to: REM set 32 bit C Compiler set c32_ROOT = C:\Program Files\Microsoft Visual Studio REM set DirectX SDK Path Set DXSDKROOT=C:\mssdk but i still get the same errors. can anybody help solve this problem?
oops...
For the DDraw errors
Link ddraw.lib

For the _main error:
Create your projectas a Win32 pplication not a consol application.


I will not make a list of links... I will not make a list of links... I will not make a list of links...
Invader''s Realm
Advertisement
I think that #include"ddrawex.h" is better, although i dont know for sure. I had that, and in the normal ddraw the LPDIRECTDRAWSURFACE7 is not declared, only LPDIRECTDRAWSURFACE.
Make sure the order of your include and lib directories is set up properly in the Visual C++ Options dialog.

Any user-installed DirectX SDK include and lib directories should be ABOVE the rest to ensure they''re looked in first.

Then you should just be able to #include <ddraw.h> and link to ddraw.lib and dxguid.lib.

Helpful links:
How To Ask Questions The Smart Way | Google can help with your question | Search MSDN for help with standard C or Windows functions
first off, the win32 app did get rid of the _main error. as for the ddraw.lib, i'm not quite sure how to link the .lib file.

with the ddrawex.h i still got the same errors.

my directories are set up as:
C:\MSSDK\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE

so i'm still stuck with the other two errors:
dex2.obj : error LNK2001: unresolved external symbol _DirectDrawCreateEx@16
ddex2.obj : error LNK2001: unresolved external symbol _IID_IDirectDraw7

so if anybody can tell me how to link to the .lib files i might be able to get rid of the other errors.

[edited by - oni_viper on July 24, 2002 5:56:50 PM]
oops...
You''re using VC++ so...

Menu: Project->Settings->Link Tab

Under Object/Library and Modules (where you see kernel32.lib etc) add ddraw.lib and dxguid.lib


I will not make a list of links... I will not make a list of links... I will not make a list of links...
Invader''s Realm
Advertisement
thanks, that fixed the linking errors. but now there''s another problem (sometimes i wonder if directx is worth it). when i run the program, it crashes and message comes up saying DDReLoadBitmap FAILED. what can i do to fix this? i hate to keep asking, the problems just never stop.
oops...
Sorry, but you''re going to have to give more information than "it failed". Perhaps some code?


I will not make a list of links... I will not make a list of links... I will not make a list of links...
Invader''s Realm
there are 3 programs. don't judge me on the code, these are examples that came with directx

1) DDEx2.CPP


  //-----------------------------------------------------------------------------// File: DDEx2.CPP//// Desc: Direct Draw example program 2.  Adds functionality to //       example program 1.  Changes the video mode to 640x480x8.//       Reads a bitmap file from disk and copies it into the //       back buffer and then slowly flips between the primary//       surface and the back buffer.  Press F12 to exit the program.//// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------//#ifndef WIN32_LEAN_AND_MEAN//#define WIN32_LEAN_AND_MEAN//#endif//-----------------------------------------------------------------------------// Include files//-----------------------------------------------------------------------------#include <windows.h>#include <ddraw.h>#include <stdio.h>#include <stdarg.h>#include "resource.h"#include "ddutil.h"//-----------------------------------------------------------------------------// Local definitions//-----------------------------------------------------------------------------#define NAME                "DDExample2"#define TITLE               "Direct Draw Example 2"//-----------------------------------------------------------------------------// Default settings//-----------------------------------------------------------------------------#define TIMER_ID            1#define TIMER_RATE          500//-----------------------------------------------------------------------------// Global data//-----------------------------------------------------------------------------LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw objectLPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surfaceLPDIRECTDRAWSURFACE7        g_pDDSBack = NULL;   // DirectDraw back surfaceLPDIRECTDRAWPALETTE         g_pDDPal = NULL;     // The primary surface paletteBOOL                        g_bActive = FALSE;   // Is application active?//-----------------------------------------------------------------------------// Local data//-----------------------------------------------------------------------------static char                 szBackground[] = "BACK";static char                 szMsg[] = "Page Flipping Test: Press F12 to exit";static char                 szFrontMsg[] = "Front buffer (F12 to quit)";static char                 szBackMsg[] = "Back buffer (F12 to quit)";//-----------------------------------------------------------------------------// Name: ReleaseAllObjects()// Desc: Finished with all objects we use; release them//-----------------------------------------------------------------------------static voidReleaseAllObjects(void){    if (g_pDD != NULL)    {        if (g_pDDSPrimary != NULL)        {            g_pDDSPrimary->Release();            g_pDDSPrimary = NULL;        }        if (g_pDDPal != NULL)        {            g_pDDPal->Release();            g_pDDPal = NULL;        }        g_pDD->Release();        g_pDD = NULL;    }}//-----------------------------------------------------------------------------// Name: InitFail()// Desc: This function is called if an initialization function fails//-----------------------------------------------------------------------------HRESULTInitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...){    char                        szBuff[128];    va_list                     vl;    va_start(vl, szError);    vsprintf(szBuff, szError, vl);    ReleaseAllObjects();    MessageBox(hWnd, szBuff, TITLE, MB_OK);    DestroyWindow(hWnd);    va_end(vl);    return hRet;}//-----------------------------------------------------------------------------// Name: UpdateFrame()// Desc: Displays the proper text for the page//-----------------------------------------------------------------------------static voidUpdateFrame(HWND hWnd){    static BYTE                 phase = 0;    HDC                         hdc;    RECT                        rc;    SIZE                        size;    // The back buffer already has a loaded bitmap, so don't clear it    if (g_pDDSBack->GetDC(&hdc) == DD_OK)    {        SetBkColor(hdc, RGB(0, 0, 255));        SetTextColor(hdc, RGB(255, 255, 0));        if (phase)        {            GetClientRect(hWnd, &rc);            GetTextExtentPoint(hdc, szMsg, lstrlen(szMsg), &size);            TextOut(hdc, (rc.right - size.cx) / 2, (rc.bottom - size.cy) / 2,                    szMsg, sizeof(szMsg) - 1);            TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));            phase = 0;        }        else        {            TextOut(hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));            phase = 1;        }        g_pDDSBack->ReleaseDC(hdc);    }}//-----------------------------------------------------------------------------// Name: WindowProc()// Desc: The Main Window Procedure//-----------------------------------------------------------------------------long FAR PASCALWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){    HRESULT                     hRet;    switch (message)    {        case WM_ACTIVATE:            // Pause if minimized            g_bActive = !((BOOL)HIWORD(wParam));            return 0L;        case WM_DESTROY:            // Clean up and close the app            ReleaseAllObjects();            PostQuitMessage(0);            return 0L;        case WM_KEYDOWN:            // Handle any non-accelerated key commands            switch (wParam)            {                case VK_ESCAPE:                case VK_F12:                    PostMessage(hWnd, WM_CLOSE, 0, 0);                    return 0L;            }            break;        case WM_SETCURSOR:            // Turn off the cursor since this is a full-screen app            SetCursor(NULL);            return TRUE;        case WM_TIMER:            // Update and flip surfaces            if (g_bActive && TIMER_ID == wParam)            {                UpdateFrame(hWnd);                while (TRUE)                {                    hRet = g_pDDSPrimary->Flip(NULL, 0);                    if (hRet == DD_OK)                        break;                    if (hRet == DDERR_SURFACELOST)                    {                        hRet = g_pDDSPrimary->Restore();                        if (hRet != DD_OK)                            break;                        hRet = DDReLoadBitmap(g_pDDSBack, szBackground);                        if (hRet != DD_OK)                            break;                    }                    if (hRet != DDERR_WASSTILLDRAWING)                        break;                }            }            break;    }    return DefWindowProc(hWnd, message, wParam, lParam);}//-----------------------------------------------------------------------------// Name: InitApp()// Desc: Do work required for every instance of the application://          Create the window, initialize data//-----------------------------------------------------------------------------static HRESULTInitApp(HINSTANCE hInstance, int nCmdShow){    HWND                        hWnd;    WNDCLASS                    wc;    DDSURFACEDESC2              ddsd;    DDSCAPS2                    ddscaps;    HRESULT                     hRet;    // Set up and register window class    wc.style = CS_HREDRAW | CS_VREDRAW;    wc.lpfnWndProc = WindowProc;    wc.cbClsExtra = 0;    wc.cbWndExtra = 0;    wc.hInstance = hInstance;    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));    wc.hCursor = LoadCursor(NULL, IDC_ARROW);    wc.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);    wc.lpszMenuName = NAME;    wc.lpszClassName = NAME;    RegisterClass(&wc);    // Create a window    hWnd = CreateWindowEx(WS_EX_TOPMOST,                          NAME,                          TITLE,                          WS_POPUP,                          0,                          0,                          GetSystemMetrics(SM_CXSCREEN),                          GetSystemMetrics(SM_CYSCREEN),                          NULL,                          NULL,                          hInstance,                          NULL);    if (!hWnd)        return FALSE;    ShowWindow(hWnd, nCmdShow);    UpdateWindow(hWnd);    SetFocus(hWnd);    ///////////////////////////////////////////////////////////////////////////    // Create the main DirectDraw object    ///////////////////////////////////////////////////////////////////////////    hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "DirectDrawCreateEx FAILED");    // Get exclusive mode    hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "SetCooperativeLevel FAILED");    // Set the video mode to 640x480x8    hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "SetDisplayMode FAILED");    // Create the primary surface with 1 back buffer    ZeroMemory(&ddsd, sizeof(ddsd));    ddsd.dwSize = sizeof(ddsd);    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |        DDSCAPS_FLIP |        DDSCAPS_COMPLEX;    ddsd.dwBackBufferCount = 1;    hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "CreateSurface FAILED");    // Get a pointer to the back buffer    ZeroMemory(&ddscaps, sizeof(ddscaps));    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;    hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "GetAttachedSurface FAILED");    // Create and set the palette    g_pDDPal = DDLoadPalette(g_pDD, szBackground);    if (g_pDDPal == NULL)        return InitFail(hWnd, hRet, "DDLoadPalette FAILED");    hRet = g_pDDSPrimary->SetPalette(g_pDDPal);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "SetPalette FAILED");    // Load a bitmap into the back buffer.    hRet = DDReLoadBitmap(g_pDDSBack, szBackground);    if (hRet != DD_OK)        return InitFail(hWnd, hRet, "DDReLoadBitmap FAILED");    // Create a timer to flip the pages    if (TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL))        return InitFail(hWnd, hRet, "SetTimer FAILED");    return DD_OK;}//-----------------------------------------------------------------------------// Name: WinMain()// Desc: Initialization, message loop//-----------------------------------------------------------------------------int PASCALWinMain(HINSTANCE hInstance,        HINSTANCE hPrevInstance,        LPSTR lpCmdLine,        int nCmdShow){    MSG                         msg;    if (InitApp(hInstance, nCmdShow) != DD_OK)        return FALSE;    while (GetMessage(&msg, NULL, 0, 0))    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }    return msg.wParam;}//---------------------------------------------------------------  



2) ddutil.cpp


  //-----------------------------------------------------------------------------// File: ddutil.cpp//// Desc: Routines for loading bitmap and palettes from resources////// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------#ifndef WIN32_LEAN_AND_MEAN#define WIN32_LEAN_AND_MEAN#endif//-----------------------------------------------------------------------------// Include files//-----------------------------------------------------------------------------#include <windows.h>#include <windowsx.h>#include <ddraw.h>#include "ddutil.h"//-----------------------------------------------------------------------------// Name: DDLoadBitmap()// Desc: Create a DirectDrawSurface from a bitmap resource.//-----------------------------------------------------------------------------extern "C" IDirectDrawSurface7* DDLoadBitmap( IDirectDraw7* pdd, LPCSTR szBitmap, int dx, int dy){    HBITMAP                 hbm;    BITMAP                  bm;    DDSURFACEDESC2          ddsd;    IDirectDrawSurface7    *pdds;    //    //  Try to load the bitmap as a resource, if that fails, try it as a file    //    hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, dx,                              dy, LR_CREATEDIBSECTION);    if (hbm == NULL)        hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, dx, dy,                                  LR_LOADFROMFILE | LR_CREATEDIBSECTION);    if (hbm == NULL)        return NULL;    //    // Get size of the bitmap    //    GetObject(hbm, sizeof(bm), &bm);    //    // Create a DirectDrawSurface for this bitmap    //    ZeroMemory(&ddsd, sizeof(ddsd));    ddsd.dwSize = sizeof(ddsd);    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;    ddsd.dwWidth = bm.bmWidth;    ddsd.dwHeight = bm.bmHeight;    if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK)        return NULL;    DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);    DeleteObject(hbm);    return pdds;}//-----------------------------------------------------------------------------// Name: DDReLoadBitmap()// Desc: Load a bitmap from a file or resource into a directdraw surface.//       normaly used to re-load a surface after a restore.//-----------------------------------------------------------------------------HRESULT DDReLoadBitmap( IDirectDrawSurface7* pdds, LPCSTR szBitmap){    HBITMAP                 hbm;    HRESULT                 hr;    //    //  Try to load the bitmap as a resource, if that fails, try it as a file    //    hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0,                              0, LR_CREATEDIBSECTION);    if (hbm == NULL)        hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0,                                  LR_LOADFROMFILE | LR_CREATEDIBSECTION);    if (hbm == NULL)    {        OutputDebugString("handle is null\n");        return E_FAIL;    }    hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);    if (hr != DD_OK)    {        OutputDebugString("ddcopybitmap failed\n");    }    DeleteObject(hbm);    return hr;}//-----------------------------------------------------------------------------// Name: DDCopyBitmap()// Desc: Draw a bitmap into a DirectDrawSurface//-----------------------------------------------------------------------------extern "C" HRESULTDDCopyBitmap(IDirectDrawSurface7* pdds, HBITMAP hbm, int x, int y,             int dx, int dy){    HDC                     hdcImage;    HDC                     hdc;    BITMAP                  bm;    DDSURFACEDESC2          ddsd;    HRESULT                 hr;    if (hbm == NULL || pdds == NULL)        return E_FAIL;    //    // Make sure this surface is restored.    //    pdds->Restore();    //    // Select bitmap into a memoryDC so we can use it.    //    hdcImage = CreateCompatibleDC(NULL);    if (!hdcImage)        OutputDebugString("createcompatible dc failed\n");    SelectObject(hdcImage, hbm);    //    // Get size of the bitmap    //    GetObject(hbm, sizeof(bm), &bm);    dx = dx == 0 ? bm.bmWidth : dx;     // Use the passed size, unless zero    dy = dy == 0 ? bm.bmHeight : dy;    //    // Get size of surface.    //    ddsd.dwSize = sizeof(ddsd);    ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;    pdds->GetSurfaceDesc(&ddsd);    if ((hr = pdds->GetDC(&hdc)) == DD_OK)    {        StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y,                   dx, dy, SRCCOPY);        pdds->ReleaseDC(hdc);    }    DeleteDC(hdcImage);    return hr;}//-----------------------------------------------------------------------------// Name: DDLoadPalette()// Desc: Create a DirectDraw palette object from a bitmap resource//       if the resource does not exist or NULL is passed create a//       default 332 palette.//-----------------------------------------------------------------------------extern "C" IDirectDrawPalette *DDLoadPalette(IDirectDraw7* pdd, LPCSTR szBitmap){    IDirectDrawPalette     *ddpal;    int                     i;    int                     n;    int                     fh;    HRSRC                   h;    LPBITMAPINFOHEADER      lpbi;    PALETTEENTRY            ape[256];    RGBQUAD                *prgb;    //    // Build a 332 palette as the default.    //    for (i = 0; i < 256; i++)    {        ape[i].peRed = (BYTE) (((i >> 5) & 0x07) * 255 / 7);        ape[i].peGreen = (BYTE) (((i >> 2) & 0x07) * 255 / 7);        ape[i].peBlue = (BYTE) (((i >> 0) & 0x03) * 255 / 3);        ape[i].peFlags = (BYTE) 0;    }    //    // Get a pointer to the bitmap resource.    //    if (szBitmap && (h = FindResource(NULL, szBitmap, RT_BITMAP)))    {        lpbi = (LPBITMAPINFOHEADER) LockResource(LoadResource(NULL, h));        if (!lpbi)            OutputDebugString("lock resource failed\n");        prgb = (RGBQUAD *) ((BYTE *) lpbi + lpbi->biSize);        if (lpbi == NULL || lpbi->biSize < sizeof(BITMAPINFOHEADER))            n = 0;        else if (lpbi->biBitCount > 8)            n = 0;        else if (lpbi->biClrUsed == 0)            n = 1 << lpbi->biBitCount;        else            n = lpbi->biClrUsed;        //        //  A DIB color table has its colors stored BGR not RGB        //  so flip them around.        //        for (i = 0; i < n; i++)        {            ape[i].peRed = prgb[i].rgbRed;            ape[i].peGreen = prgb[i].rgbGreen;            ape[i].peBlue = prgb[i].rgbBlue;            ape[i].peFlags = 0;        }    }    else if (szBitmap && (fh = _lopen(szBitmap, OF_READ)) != -1)    {        BITMAPFILEHEADER        bf;        BITMAPINFOHEADER        bi;        _lread(fh, &bf, sizeof(bf));        _lread(fh, &bi, sizeof(bi));        _lread(fh, ape, sizeof(ape));        _lclose(fh);        if (bi.biSize != sizeof(BITMAPINFOHEADER))            n = 0;        else if (bi.biBitCount > 8)            n = 0;        else if (bi.biClrUsed == 0)            n = 1 << bi.biBitCount;        else            n = bi.biClrUsed;        //        //  A DIB color table has its colors stored BGR not RGB        //  so flip them around.        //        for (i = 0; i < n; i++)        {            BYTE        r = ape[i].peRed;            ape[i].peRed = ape[i].peBlue;            ape[i].peBlue = r;        }    }    pdd->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);    return ddpal;}//-----------------------------------------------------------------------------// Name: DDColorMatch()// Desc: Convert a RGB color to a pysical color.//       We do this by leting GDI SetPixel() do the color matching//       then we lock the memory and see what it got mapped to.//-----------------------------------------------------------------------------extern "C" DWORDDDColorMatch(IDirectDrawSurface7* pdds, COLORREF rgb){    COLORREF                rgbT;    HDC                     hdc;    DWORD                   dw = CLR_INVALID;    DDSURFACEDESC2          ddsd;    HRESULT                 hres;    //    //  Use GDI SetPixel to color match for us    //    if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)    {        rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value        SetPixel(hdc, 0, 0, rgb);       // Set our value        pdds->ReleaseDC(hdc);    }    //    // Now lock the surface so we can read back the converted color    //    ddsd.dwSize = sizeof(ddsd);    while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)        ;    if (hres == DD_OK)    {        dw = *(DWORD *) ddsd.lpSurface;                 // Get DWORD        if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)            dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;  // Mask it to bpp        pdds->Unlock(NULL);    }    //    //  Now put the color that was there back.    //    if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)    {        SetPixel(hdc, 0, 0, rgbT);        pdds->ReleaseDC(hdc);    }    return dw;}//-----------------------------------------------------------------------------// Name: DDSetColorKey()// Desc: Set a color key for a surface, given a RGB.//       If you pass CLR_INVALID as the color key, the pixel//       in the upper-left corner will be used.//-----------------------------------------------------------------------------extern "C" HRESULTDDSetColorKey(IDirectDrawSurface7* pdds, COLORREF rgb){    DDCOLORKEY              ddck;    ddck.dwColorSpaceLowValue = DDColorMatch(pdds, rgb);    ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;    return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck);}//--------------------------------------------------------------  



3) resource.h


  #define IDI_MAIN_ICON                   101#define IDR_MENU                        102#define IDM_EXIT                        40001  



that's all the code, and a lot too. i'm not really sure whats wrong with it. all i know is that it compiles and links fine, but crashes while running.

[edited by - oni_viper on July 25, 2002 2:00:02 AM]
oops...
Two words....

Code Tags.

This topic is closed to new replies.

Advertisement